Version 1.15.0-dev.5.0

Merge commit 'a28bfa98796cfc31676211f474b1c6e0ee68f776' into dev
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a4cf5bf..dd219f6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,28 +1,39 @@
 ## 1.15.0
 
+### Language features
+* Added support for [configuration-specific imports](https://github.com/munificent/dep-interface-libraries/blob/master/Proposal.md).
+  On the VM and dart2js, they can be enabled with `--conditional-directives`.
+
+  The analyzer requires an additional option in an `options` file:
+  ```yaml
+  analyzer:
+    language:
+      enableConditionalDirectives: true
+  ```
+  Then run the analyzer with `--options=<path-to-options-file>`.
+
 ### Core library changes
+
+* `dart:async`
+  * Made `StreamView` class a `const` class.
+
+* `dart:core`
   * Added `Uri.queryParametersAll` to handle multiple query parameters with
     the same name.
 
 * `dart:io`
   * Added `SecurityContext.usePrivateKeyBytes`,
-          `SecurityContext.useCertificateChainBytes`,
-          `SecurityContext.setTrustedCertificatesBytes`, and
-          `SecurityContext.setClientAuthoritiesBytes`.
-  * The non-`Bytes` methods of `SecurityContext` are being renamed -`Sync`, as
-    they will do synchronous IO. The non-`Bytes` and non-`Sync` methods are
-    deprecated and will be removed in a later release.
+    `SecurityContext.useCertificateChainBytes`,
+    `SecurityContext.setTrustedCertificatesBytes`, and
+    `SecurityContext.setClientAuthoritiesBytes`.
   * **Breaking** The named `directory` argument of
-    `SecurityContext.setTrustedCertificates` is no longer supported.
-    The method now only supports one argument for the PEM file name containing
-    the trusted certificates.
-  * Added support to SecurityContext for PKCS12 certificate and key containers.
+    `SecurityContext.setTrustedCertificates` has been removed.
+  * Added support to `SecurityContext` for PKCS12 certificate and key
+    containers.
   * All calls in `SecurityContext` that accept certificate data now accept an
     optional named parameter `password`, similar to
     `SecurityContext.usePrivateKeyBytes`, for use as the password for PKCS12
     data.
-* `dart:async`
-  * Made `StreamView` class a `const` class.
 
 ## 1.14.2 - 2016-02-09
 
diff --git a/DEPS b/DEPS
index 274afa0..38ccb51 100644
--- a/DEPS
+++ b/DEPS
@@ -292,10 +292,6 @@
 # without the runtime being available.
 hooks = [
   {
-    "pattern": ".",
-    "action": ["python", Var("dart_root") + "/tools/gyp_dart.py"],
-  },
-  {
     'name': 'd8_testing_binaries',
     'pattern': '.',
     'action': [
@@ -429,4 +425,8 @@
       Var('dart_root') + "/third_party/clang.tar.gz.sha1",
     ],
   },
+  {
+    "pattern": ".",
+    "action": ["python", Var("dart_root") + "/tools/gyp_dart.py"],
+  },
 ]
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index df9075e..887c34b 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -116,6 +116,12 @@
   final ServerPlugin serverPlugin;
 
   /**
+   * A list of the globs used to determine which files should be analyzed. The
+   * list is lazily created and should be accessed using [analyzedFilesGlobs].
+   */
+  List<Glob> _analyzedFilesGlobs = null;
+
+  /**
    * The [ContextManager] that handles the mapping from analysis roots to
    * context directories.
    */
@@ -156,12 +162,6 @@
   final InstrumentationService instrumentationService;
 
   /**
-   * A table mapping [Folder]s to the [AnalysisContext]s associated with them.
-   */
-  final Map<Folder, AnalysisContext> folderMap =
-      new HashMap<Folder, AnalysisContext>();
-
-  /**
    * A queue of the operations to perform in this server.
    */
   ServerOperationQueue operationQueue;
@@ -280,9 +280,10 @@
   Set<String> prevAnalyzedFiles;
 
   /**
-   * The default options used to create new analysis contexts.
+   * The default options used to create new analysis contexts. This object is
+   * also referenced by the ContextManager.
    */
-  AnalysisOptionsImpl defaultContextOptions = new AnalysisOptionsImpl();
+  final AnalysisOptionsImpl defaultContextOptions = new AnalysisOptionsImpl();
 
   /**
    * The controller for sending [ContextsChangedEvent]s.
@@ -314,22 +315,24 @@
       : index = _index,
         searchEngine = _index != null ? createSearchEngine(_index) : null {
     _performance = performanceDuringStartup;
-    operationQueue = new ServerOperationQueue();
-    contextManager = new ContextManagerImpl(
-        resourceProvider,
-        packageResolverProvider,
-        embeddedResolverProvider,
-        packageMapProvider,
-        instrumentationService);
-    ServerContextManagerCallbacks contextManagerCallbacks =
-        new ServerContextManagerCallbacks(this, resourceProvider);
-    contextManager.callbacks = contextManagerCallbacks;
     defaultContextOptions.incremental = true;
     defaultContextOptions.incrementalApi =
         options.enableIncrementalResolutionApi;
     defaultContextOptions.incrementalValidation =
         options.enableIncrementalResolutionValidation;
     defaultContextOptions.generateImplicitErrors = false;
+    operationQueue = new ServerOperationQueue();
+    contextManager = new ContextManagerImpl(
+        resourceProvider,
+        packageResolverProvider,
+        embeddedResolverProvider,
+        packageMapProvider,
+        analyzedFilesGlobs,
+        instrumentationService,
+        defaultContextOptions);
+    ServerContextManagerCallbacks contextManagerCallbacks =
+        new ServerContextManagerCallbacks(this, resourceProvider);
+    contextManager.callbacks = contextManagerCallbacks;
     _noErrorNotification = options.noErrorNotification;
     AnalysisEngine.instance.logger = new AnalysisLogger(this);
     _onAnalysisStartedController = new StreamController.broadcast();
@@ -352,6 +355,40 @@
   }
 
   /**
+   * Return the [AnalysisContext]s that are being used to analyze the analysis
+   * roots.
+   */
+  Iterable<AnalysisContext> get analysisContexts =>
+      contextManager.analysisContexts;
+
+  /**
+   * Return a list of the globs used to determine which files should be analyzed.
+   */
+  List<Glob> get analyzedFilesGlobs {
+    if (_analyzedFilesGlobs == null) {
+      _analyzedFilesGlobs = <Glob>[];
+      List<String> patterns = serverPlugin.analyzedFilePatterns;
+      for (String pattern in patterns) {
+        try {
+          _analyzedFilesGlobs
+              .add(new Glob(JavaFile.pathContext.separator, pattern));
+        } catch (exception, stackTrace) {
+          AnalysisEngine.instance.logger.logError(
+              'Invalid glob pattern: "$pattern"',
+              new CaughtException(exception, stackTrace));
+        }
+      }
+    }
+    return _analyzedFilesGlobs;
+  }
+
+  /**
+   * Return a table mapping [Folder]s to the [AnalysisContext]s associated with
+   * them.
+   */
+  Map<Folder, AnalysisContext> get folderMap => contextManager.folderMap;
+
+  /**
    * The [Future] that completes when analysis is complete.
    */
   Future get onAnalysisComplete {
@@ -462,7 +499,7 @@
    * explicitly or implicitly.  Return `null` if there is no such context.
    */
   AnalysisContext getAnalysisContextForSource(Source source) {
-    for (AnalysisContext context in folderMap.values) {
+    for (AnalysisContext context in analysisContexts) {
       SourceKind kind = context.getKindOf(source);
       if (kind != SourceKind.UNKNOWN) {
         return context;
@@ -471,14 +508,6 @@
     return null;
   }
 
-  /**
-   * Return the [AnalysisContext]s that are being used to analyze the analysis
-   * roots.
-   */
-  Iterable<AnalysisContext> getAnalysisContexts() {
-    return folderMap.values;
-  }
-
   CompilationUnitElement getCompilationUnitElement(String file) {
     ContextSourcePair pair = getContextSourcePair(file);
     if (pair == null) {
@@ -554,7 +583,7 @@
       }
     }
     // try to find a context that analysed the file
-    for (AnalysisContext context in folderMap.values) {
+    for (AnalysisContext context in analysisContexts) {
       Source source = ContextManagerImpl.createSourceInContext(context, file);
       SourceKind kind = context.getKindOf(source);
       if (kind != SourceKind.UNKNOWN) {
@@ -562,7 +591,7 @@
       }
     }
     // try to find a context for which the file is a priority source
-    for (InternalAnalysisContext context in folderMap.values) {
+    for (InternalAnalysisContext context in analysisContexts) {
       List<Source> sources = context.getSourcesWithFullName(path);
       if (sources.isNotEmpty) {
         Source source = sources.first;
@@ -612,23 +641,6 @@
     return elements;
   }
 
-// TODO(brianwilkerson) Add the following method after 'prioritySources' has
-// been added to InternalAnalysisContext.
-//  /**
-//   * Return a list containing the full names of all of the sources that are
-//   * priority sources.
-//   */
-//  List<String> getPriorityFiles() {
-//    List<String> priorityFiles = new List<String>();
-//    folderMap.values.forEach((ContextDirectory directory) {
-//      InternalAnalysisContext context = directory.context;
-//      context.prioritySources.forEach((Source source) {
-//        priorityFiles.add(source.fullName);
-//      });
-//    });
-//    return priorityFiles;
-//  }
-
   /**
    * Return an analysis error info containing the array of all of the errors and
    * the line info associated with [file].
@@ -655,6 +667,23 @@
     return context.getErrors(source);
   }
 
+// TODO(brianwilkerson) Add the following method after 'prioritySources' has
+// been added to InternalAnalysisContext.
+//  /**
+//   * Return a list containing the full names of all of the sources that are
+//   * priority sources.
+//   */
+//  List<String> getPriorityFiles() {
+//    List<String> priorityFiles = new List<String>();
+//    folderMap.values.forEach((ContextDirectory directory) {
+//      InternalAnalysisContext context = directory.context;
+//      context.prioritySources.forEach((Source source) {
+//        priorityFiles.add(source.fullName);
+//      });
+//    });
+//    return priorityFiles;
+//  }
+
   /**
    * Returns resolved [AstNode]s at the given [offset] of the given [file].
    *
@@ -1114,7 +1143,7 @@
       if (preferredContext == null) {
         Resource resource = resourceProvider.getResource(file);
         if (resource is File && resource.exists) {
-          for (AnalysisContext context in folderMap.values) {
+          for (AnalysisContext context in analysisContexts) {
             Uri uri = context.sourceFactory.restoreUri(source);
             if (uri.scheme != 'file') {
               preferredContext = context;
@@ -1131,7 +1160,7 @@
         sourceMap.putIfAbsent(preferredContext, () => <Source>[]).add(source);
         contextFound = true;
       }
-      for (AnalysisContext context in folderMap.values) {
+      for (AnalysisContext context in analysisContexts) {
         if (context != preferredContext &&
             context.getKindOf(source) != SourceKind.UNKNOWN) {
           sourceMap.putIfAbsent(context, () => <Source>[]).add(source);
@@ -1245,7 +1274,7 @@
       // If the source does not exist, then it was an overlay-only one.
       // Remove it from contexts.
       if (newContents == null && !source.exists()) {
-        for (InternalAnalysisContext context in folderMap.values) {
+        for (InternalAnalysisContext context in analysisContexts) {
           List<Source> sources = context.getSourcesWithFullName(file);
           ChangeSet changeSet = new ChangeSet();
           sources.forEach(changeSet.removedSource);
@@ -1256,7 +1285,7 @@
       }
       // Update all contexts.
       bool anyContextUpdated = false;
-      for (InternalAnalysisContext context in folderMap.values) {
+      for (InternalAnalysisContext context in analysisContexts) {
         List<Source> sources = context.getSourcesWithFullName(file);
         sources.forEach((Source source) {
           anyContextUpdated = true;
@@ -1313,7 +1342,7 @@
     //
     // Update existing contexts.
     //
-    folderMap.forEach((Folder folder, AnalysisContext context) {
+    for (AnalysisContext context in analysisContexts) {
       AnalysisOptionsImpl options =
           new AnalysisOptionsImpl.from(context.analysisOptions);
       optionUpdaters.forEach((OptionUpdater optionUpdater) {
@@ -1322,7 +1351,7 @@
       context.analysisOptions = options;
       // TODO(brianwilkerson) As far as I can tell, this doesn't cause analysis
       // to be scheduled for this context.
-    });
+    }
     //
     // Update the defaults used to create new contexts.
     //
@@ -1331,6 +1360,14 @@
     });
   }
 
+  void _computingPackageMap(bool computing) {
+    if (serverServices.contains(ServerService.STATUS)) {
+      PubStatus pubStatus = new PubStatus(computing);
+      ServerStatusParams params = new ServerStatusParams(pub: pubStatus);
+      sendNotification(params.toNotification());
+    }
+  }
+
   /**
    * Return a set of all contexts whose associated folder is contained within,
    * or equal to, one of the resources in the given list of [resources].
@@ -1451,39 +1488,8 @@
    */
   final ResourceProvider resourceProvider;
 
-  /**
-   * A list of the globs used to determine which files should be analyzed. The
-   * list is lazily created and should be accessed using [analyzedFilesGlobs].
-   */
-  List<Glob> _analyzedFilesGlobs = null;
-
   ServerContextManagerCallbacks(this.analysisServer, this.resourceProvider);
 
-  /**
-   * Return a list of the globs used to determine which files should be analyzed.
-   */
-  List<Glob> get analyzedFilesGlobs {
-    if (_analyzedFilesGlobs == null) {
-      _analyzedFilesGlobs = <Glob>[];
-      List<String> patterns = analysisServer.serverPlugin.analyzedFilePatterns;
-      for (String pattern in patterns) {
-        try {
-          _analyzedFilesGlobs
-              .add(new Glob(JavaFile.pathContext.separator, pattern));
-        } catch (exception, stackTrace) {
-          AnalysisEngine.instance.logger.logError(
-              'Invalid glob pattern: "$pattern"',
-              new CaughtException(exception, stackTrace));
-        }
-      }
-    }
-    return _analyzedFilesGlobs;
-  }
-
-  @override
-  AnalysisOptions get defaultAnalysisOptions =>
-      analysisServer.defaultContextOptions;
-
   @override
   AnalysisContext addContext(
       Folder folder, AnalysisOptions options, FolderDisposition disposition) {
@@ -1518,14 +1524,8 @@
   }
 
   @override
-  void beginComputePackageMap() {
-    _computingPackageMap(true);
-  }
-
-  @override
-  void endComputePackageMap() {
-    _computingPackageMap(false);
-  }
+  void computingPackageMap(bool computing) =>
+      analysisServer._computingPackageMap(computing);
 
   @override
   void removeContext(Folder folder, List<String> flushedFiles) {
@@ -1544,22 +1544,6 @@
   }
 
   @override
-  bool shouldFileBeAnalyzed(File file) {
-    for (Glob glob in analyzedFilesGlobs) {
-      if (glob.matches(file.path)) {
-        // Emacs creates dummy links to track the fact that a file is open for
-        // editing and has unsaved changes (e.g. having unsaved changes to
-        // 'foo.dart' causes a link '.#foo.dart' to be created, which points to
-        // the non-existent file 'username@hostname.pid'. To avoid these dummy
-        // links causing the analyzer to thrash, just ignore links to
-        // non-existent files.
-        return file.exists;
-      }
-    }
-    return false;
-  }
-
-  @override
   void updateContextPackageUriResolver(
       Folder contextFolder, FolderDisposition disposition) {
     AnalysisContext context = analysisServer.folderMap[contextFolder];
@@ -1570,14 +1554,6 @@
     analysisServer.schedulePerformAnalysisOperation(context);
   }
 
-  void _computingPackageMap(bool computing) {
-    if (analysisServer.serverServices.contains(ServerService.STATUS)) {
-      PubStatus pubStatus = new PubStatus(computing);
-      ServerStatusParams params = new ServerStatusParams(pub: pubStatus);
-      analysisServer.sendNotification(params.toNotification());
-    }
-  }
-
   /**
    * Set up a [SourceFactory] that resolves packages as appropriate for the
    * given [disposition].
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index 8575086..c81ce7f 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -31,6 +31,7 @@
 import 'package:analyzer/src/generated/source_io.dart';
 import 'package:analyzer/src/task/options.dart';
 import 'package:analyzer/src/util/absolute_path.dart';
+import 'package:analyzer/src/util/glob.dart';
 import 'package:analyzer/src/util/yaml.dart';
 import 'package:package_config/packages.dart';
 import 'package:package_config/packages_file.dart' as pkgfile show parse;
@@ -228,6 +229,12 @@
   // TODO(brianwilkerson) Move this class to a public library.
 
   /**
+   * Return the [AnalysisContext]s that are being used to analyze the analysis
+   * roots.
+   */
+  Iterable<AnalysisContext> get analysisContexts;
+
+  /**
    * Get the callback interface used to create, destroy, and update contexts.
    */
   ContextManagerCallbacks get callbacks;
@@ -244,6 +251,12 @@
   List<String> get excludedPaths;
 
   /**
+   * Return a table mapping [Folder]s to the [AnalysisContext]s associated with
+   * them.
+   */
+  Map<Folder, AnalysisContext> get folderMap;
+
+  /**
    * Return the list of included paths (folders and files) most recently passed
    * to [setRoots].
    */
@@ -307,12 +320,6 @@
  */
 abstract class ContextManagerCallbacks {
   /**
-   * Return the default analysis options to be used when creating an analysis
-   * context.
-   */
-  AnalysisOptions get defaultAnalysisOptions;
-
-  /**
    * Create and return a new analysis context rooted at the given [folder], with
    * the given analysis [options], allowing [disposition] to govern details of
    * how the context is to be created.
@@ -328,19 +335,10 @@
   void applyChangesToContext(Folder contextFolder, ChangeSet changeSet);
 
   /**
-   * Called when the ContextManager is about to start computing the package
-   * map.
+   * Signals that the context manager has started to compute a package map (if
+   * [computing] is `true`) or has finished (if [computing] is `false`).
    */
-  void beginComputePackageMap() {
-    // By default, do nothing.
-  }
-
-  /**
-   * Called when the ContextManager has finished computing the package map.
-   */
-  void endComputePackageMap() {
-    // By default, do nothing.
-  }
+  void computingPackageMap(bool computing);
 
   /**
    * Remove the context associated with the given [folder].  [flushedFiles] is
@@ -350,11 +348,6 @@
   void removeContext(Folder folder, List<String> flushedFiles);
 
   /**
-   * Return `true` if the given [file] should be analyzed.
-   */
-  bool shouldFileBeAnalyzed(File file);
-
-  /**
    * Called when the disposition for a context has changed.
    */
   void updateContextPackageUriResolver(
@@ -456,6 +449,16 @@
       new AnalysisOptionsProvider();
 
   /**
+   * A list of the globs used to determine which files should be analyzed.
+   */
+  final List<Glob> analyzedFilesGlobs;
+
+  /**
+   * The default options used to create new analysis contexts.
+   */
+  final AnalysisOptionsImpl defaultContextOptions;
+
+  /**
    * The instrumentation service used to report instrumentation data.
    */
   final InstrumentationService _instrumentationService;
@@ -470,6 +473,13 @@
   final ContextInfo rootInfo = new ContextInfo._root();
 
   /**
+   * A table mapping [Folder]s to the [AnalysisContext]s associated with them.
+   */
+  @override
+  final Map<Folder, AnalysisContext> folderMap =
+      new HashMap<Folder, AnalysisContext>();
+
+  /**
    * Stream subscription we are using to watch each analysis root directory for
    * changes.
    */
@@ -481,12 +491,17 @@
       this.packageResolverProvider,
       this.embeddedUriResolverProvider,
       this._packageMapProvider,
-      this._instrumentationService) {
+      this.analyzedFilesGlobs,
+      this._instrumentationService,
+      this.defaultContextOptions) {
     absolutePathContext = resourceProvider.absolutePathContext;
     pathContext = resourceProvider.pathContext;
   }
 
   @override
+  Iterable<AnalysisContext> get analysisContexts => folderMap.values;
+
+  @override
   List<AnalysisContext> contextsInAnalysisRoot(Folder analysisRoot) {
     List<AnalysisContext> contexts = <AnalysisContext>[];
     ContextInfo innermostContainingInfo =
@@ -783,7 +798,7 @@
       // add files, recurse into folders
       if (child is File) {
         // ignore if should not be analyzed at all
-        if (!callbacks.shouldFileBeAnalyzed(child)) {
+        if (!_shouldFileBeAnalyzed(child)) {
           continue;
         }
         // ignore if was not excluded
@@ -830,7 +845,7 @@
       }
       // add files, recurse into folders
       if (child is File) {
-        if (callbacks.shouldFileBeAnalyzed(child)) {
+        if (_shouldFileBeAnalyzed(child)) {
           Source source = createSourceInContext(info.context, child);
           changeSet.addedSource(source);
           info.sources[path] = source;
@@ -892,7 +907,6 @@
           if (sourceFactory is SourceFactoryImpl) {
             if (!sourceFactory.resolvers
                 .any((UriResolver r) => r is EmbedderUriResolver)) {
-
               // Get all but the dart: Uri resolver.
               List<UriResolver> resolvers = sourceFactory.resolvers
                   .where((r) => r is! DartUriResolver)
@@ -995,7 +1009,7 @@
       return new NoPackageFolderDisposition(packageRoot: packageRoot);
     } else {
       PackageMapInfo packageMapInfo;
-      callbacks.beginComputePackageMap();
+      callbacks.computingPackageMap(true);
       try {
         // Try .packages first.
         if (absolutePathContext.basename(packagespecFile.path) ==
@@ -1014,7 +1028,7 @@
           packageMapInfo = _packageMapProvider.computePackageMap(folder);
         });
       } finally {
-        callbacks.endComputePackageMap();
+        callbacks.computingPackageMap(false);
       }
       for (String dependencyPath in packageMapInfo.dependencies) {
         addDependency(dependencyPath);
@@ -1046,7 +1060,7 @@
 
     Map<String, Object> optionMap = readOptions(info.folder);
     AnalysisOptions options =
-        new AnalysisOptionsImpl.from(callbacks.defaultAnalysisOptions);
+        new AnalysisOptionsImpl.from(defaultContextOptions);
     applyToAnalysisOptions(options, optionMap);
 
     info.setDependencies(dependencies);
@@ -1305,7 +1319,7 @@
         // that case don't add it.
         if (resource is File) {
           File file = resource;
-          if (callbacks.shouldFileBeAnalyzed(file)) {
+          if (_shouldFileBeAnalyzed(file)) {
             ChangeSet changeSet = new ChangeSet();
             Source source = createSourceInContext(info.context, file);
             changeSet.addedSource(source);
@@ -1489,6 +1503,24 @@
   }
 
   /**
+   * Return `true` if the given [file] should be analyzed.
+   */
+  bool _shouldFileBeAnalyzed(File file) {
+    for (Glob glob in analyzedFilesGlobs) {
+      if (glob.matches(file.path)) {
+        // Emacs creates dummy links to track the fact that a file is open for
+        // editing and has unsaved changes (e.g. having unsaved changes to
+        // 'foo.dart' causes a link '.#foo.dart' to be created, which points to
+        // the non-existent file 'username@hostname.pid'. To avoid these dummy
+        // links causing the analyzer to thrash, just ignore links to
+        // non-existent files.
+        return file.exists;
+      }
+    }
+    return false;
+  }
+
+  /**
    * Create and return a source representing the given [file] within the given
    * [context].
    */
diff --git a/pkg/analysis_server/lib/src/domain_analysis.dart b/pkg/analysis_server/lib/src/domain_analysis.dart
index 0c8d28b..7bfb354 100644
--- a/pkg/analysis_server/lib/src/domain_analysis.dart
+++ b/pkg/analysis_server/lib/src/domain_analysis.dart
@@ -110,7 +110,7 @@
   Response getLibraryDependencies(Request request) {
     server.onAnalysisComplete.then((_) {
       LibraryDependencyCollector collector =
-          new LibraryDependencyCollector(server.getAnalysisContexts());
+          new LibraryDependencyCollector(server.analysisContexts);
       Set<String> libraries = collector.collectLibraryDependencies();
       Map<String, Map<String, List<String>>> packageMap =
           collector.calculatePackageMap(server.folderMap);
@@ -378,7 +378,7 @@
         .putIfAbsent(descriptor,
             () => new StreamController<engine.ComputedResult>.broadcast())
         .stream;
-    server.getAnalysisContexts().forEach(_subscribeForContext);
+    server.analysisContexts.forEach(_subscribeForContext);
     return stream;
   }
 
diff --git a/pkg/analysis_server/lib/src/domain_diagnostic.dart b/pkg/analysis_server/lib/src/domain_diagnostic.dart
index 94b1c3a..df32e9e 100644
--- a/pkg/analysis_server/lib/src/domain_diagnostic.dart
+++ b/pkg/analysis_server/lib/src/domain_diagnostic.dart
@@ -9,7 +9,6 @@
 
 import 'package:analysis_server/plugin/protocol/protocol.dart';
 import 'package:analysis_server/src/analysis_server.dart';
-import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/src/context/cache.dart';
 import 'package:analyzer/src/context/context.dart';
 import 'package:analyzer/src/generated/engine.dart';
@@ -40,15 +39,14 @@
   /// Answer the `diagnostic.diagnostics` request.
   Response computeDiagnostics(Request request) {
     List<ContextData> infos = <ContextData>[];
-    server.folderMap.forEach((Folder folder, AnalysisContext context) {
-      infos.add(extractData(folder, context));
-    });
-
+    for (AnalysisContext context in server.analysisContexts) {
+      infos.add(extractData(context));
+    }
     return new DiagnosticGetDiagnosticsResult(infos).toResponse(request.id);
   }
 
   /// Extract context data from the given [context].
-  ContextData extractData(Folder folder, AnalysisContext context) {
+  ContextData extractData(AnalysisContext context) {
     int explicitFiles = 0;
     int implicitFiles = 0;
     int workItems = 0;
diff --git a/pkg/analysis_server/lib/src/domain_execution.dart b/pkg/analysis_server/lib/src/domain_execution.dart
index 3988de2..4954152 100644
--- a/pkg/analysis_server/lib/src/domain_execution.dart
+++ b/pkg/analysis_server/lib/src/domain_execution.dart
@@ -195,7 +195,7 @@
       server.contextManager.isInAnalysisRoot(filePath);
 
   void _reportCurrentFileStatus() {
-    for (AnalysisContext context in server.getAnalysisContexts()) {
+    for (AnalysisContext context in server.analysisContexts) {
       List<Source> librarySources = context.librarySources;
       List<Source> clientSources = context.launchableClientLibrarySources;
       List<Source> serverSources = context.launchableServerLibrarySources;
@@ -220,7 +220,8 @@
           List<Source> libraries =
               context.getLibrariesReferencedFromHtml(source);
           server.sendNotification(new ExecutionLaunchDataParams(filePath,
-              referencedFiles: _getFullNames(libraries)).toNotification());
+                  referencedFiles: _getFullNames(libraries))
+              .toNotification());
         }
       }
     }
diff --git a/pkg/analysis_server/lib/src/operation/operation_analysis.dart b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
index 2267250..3b2c724 100644
--- a/pkg/analysis_server/lib/src/operation/operation_analysis.dart
+++ b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
@@ -134,7 +134,7 @@
     // analysis engine to update this set incrementally as analysis is
     // performed.
     LibraryDependencyCollector collector =
-        new LibraryDependencyCollector(server.getAnalysisContexts().toList());
+        new LibraryDependencyCollector(server.analysisContexts.toList());
     Set<String> analyzedFiles = collector.collectLibraryDependencies();
     Set<String> prevAnalyzedFiles = server.prevAnalyzedFiles;
     if (prevAnalyzedFiles != null &&
diff --git a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
index be95ec1..b5a7ea2 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
@@ -287,10 +287,6 @@
 
   void _addProposal_addTypeAnnotation_VariableDeclaration() {
     AstNode node = this.node;
-    // check if "var v = 42;^"
-    if (node is VariableDeclarationStatement) {
-      node = (node as VariableDeclarationStatement).variables;
-    }
     // prepare VariableDeclarationList
     VariableDeclarationList declarationList =
         node.getAncestor((node) => node is VariableDeclarationList);
@@ -310,6 +306,11 @@
       return;
     }
     VariableDeclaration variable = variables[0];
+    // must be not after the name of the variable
+    if (selectionOffset > variable.name.end) {
+      _coverageMarker();
+      return;
+    }
     // we need an initializer to get the type from
     Expression initializer = variable.initializer;
     if (initializer == null) {
@@ -1431,44 +1432,32 @@
   }
 
   void _addProposal_removeTypeAnnotation() {
-    VariableDeclarationList variableList;
-    // try top-level variable
-    {
-      TopLevelVariableDeclaration declaration =
-          node.getAncestor((node) => node is TopLevelVariableDeclaration);
-      if (declaration != null) {
-        variableList = declaration.variables;
-      }
-    }
-    // try class field
-    if (variableList == null) {
-      FieldDeclaration fieldDeclaration =
-          node.getAncestor((node) => node is FieldDeclaration);
-      if (fieldDeclaration != null) {
-        variableList = fieldDeclaration.fields;
-      }
-    }
-    // try local variable
-    if (variableList == null) {
-      VariableDeclarationStatement statement =
-          node.getAncestor((node) => node is VariableDeclarationStatement);
-      if (statement != null) {
-        variableList = statement.variables;
-      }
-    }
-    if (variableList == null) {
+    VariableDeclarationList declarationList =
+        node.getAncestor((n) => n is VariableDeclarationList);
+    if (declarationList == null) {
       _coverageMarker();
       return;
     }
     // we need a type
-    TypeName typeNode = variableList.type;
+    TypeName typeNode = declarationList.type;
     if (typeNode == null) {
       _coverageMarker();
       return;
     }
+    // ignore if an incomplete variable declaration
+    if (declarationList.variables.length == 1 &&
+        declarationList.variables[0].name.isSynthetic) {
+      _coverageMarker();
+      return;
+    }
+    // must be not after the name of the variable
+    VariableDeclaration firstVariable = declarationList.variables[0];
+    if (selectionOffset > firstVariable.name.end) {
+      _coverageMarker();
+      return;
+    }
     // add edit
-    Token keyword = variableList.keyword;
-    VariableDeclaration firstVariable = variableList.variables[0];
+    Token keyword = declarationList.keyword;
     SourceRange typeRange = rangeStartStart(typeNode, firstVariable);
     if (keyword != null && keyword.lexeme != 'var') {
       _addReplaceEdit(typeRange, '');
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index 7525b74f..49d616d 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -8,6 +8,7 @@
 
 import 'package:analysis_server/plugin/edit/fix/fix_core.dart';
 import 'package:analysis_server/src/plugin/server_plugin.dart';
+import 'package:analysis_server/src/services/correction/fix_internal.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/error.dart';
@@ -46,8 +47,8 @@
 /**
  * Return true if this [errorCode] is likely to have a fix associated with it.
  */
-bool hasFix(ErrorCode errorCode) => errorCode ==
-        StaticWarningCode.UNDEFINED_CLASS_BOOLEAN ||
+bool hasFix(ErrorCode errorCode) =>
+    errorCode == StaticWarningCode.UNDEFINED_CLASS_BOOLEAN ||
     errorCode == StaticWarningCode.CONCRETE_CLASS_WITH_ABSTRACT_MEMBER ||
     errorCode == StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS ||
     errorCode == StaticWarningCode.NEW_WITH_UNDEFINED_CONSTRUCTOR ||
@@ -60,7 +61,8 @@
     errorCode ==
         StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FOUR ||
     errorCode ==
-        StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FIVE_PLUS ||
+        StaticWarningCode
+            .NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FIVE_PLUS ||
     errorCode == StaticWarningCode.CAST_TO_NON_TYPE ||
     errorCode == StaticWarningCode.TYPE_TEST_WITH_UNDEFINED_NAME ||
     errorCode == StaticWarningCode.UNDEFINED_CLASS ||
@@ -99,7 +101,8 @@
     errorCode == StaticTypeWarningCode.UNDEFINED_FUNCTION ||
     errorCode == StaticTypeWarningCode.UNDEFINED_GETTER ||
     errorCode == StaticTypeWarningCode.UNDEFINED_METHOD ||
-    errorCode == StaticTypeWarningCode.UNDEFINED_SETTER;
+    errorCode == StaticTypeWarningCode.UNDEFINED_SETTER ||
+    (errorCode is LintCode && errorCode.name == LintNames.annotate_overrides);
 
 /**
  * An enumeration of possible quick fix kinds.
@@ -165,6 +168,8 @@
       const FixKind('IMPORT_LIBRARY_SHOW', 49, "Update library '{0}' import");
   static const INSERT_SEMICOLON =
       const FixKind('INSERT_SEMICOLON', 50, "Insert ';'");
+  static const LINT_ADD_OVERRIDE =
+      const FixKind('LINT_ADD_OVERRIDE', 50, "Add '@override' annotation");
   static const MAKE_CLASS_ABSTRACT =
       const FixKind('MAKE_CLASS_ABSTRACT', 50, "Make class '{0}' abstract");
   static const REMOVE_DEAD_CODE =
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index 01ddada..dc66c45 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -343,6 +343,12 @@
       _addFix_undefinedClassAccessor_useSimilar();
       _addFix_createField();
     }
+    // lints
+    if (errorCode is LintCode) {
+      if (errorCode.name == LintNames.annotate_overrides) {
+        _addLintFixAddOverrideAnnotation();
+      }
+    }
     // done
     return fixes;
   }
@@ -2202,6 +2208,26 @@
     group.addPosition(position, range.length);
   }
 
+  void _addLintFixAddOverrideAnnotation() {
+    ClassMember member = node.getAncestor((n) => n is ClassMember);
+    if (member == null) {
+      return;
+    }
+
+    //TODO(pq): migrate annotation edit building to change_builder
+
+    // Handle doc comments.
+    Token token = member.beginToken;
+    if (token is CommentToken) {
+      token = (token as CommentToken).parent;
+    }
+
+    exitPosition = new Position(file, token.offset - 1);
+    String indent = utils.getIndent(1);
+    _addReplaceEdit(rf.rangeStartLength(token, 0), '@override$eol$indent');
+    _addFix(DartFixKind.LINT_ADD_OVERRIDE, []);
+  }
+
   /**
    * Prepares proposal for creating function corresponding to the given
    * [FunctionType].
@@ -2884,6 +2910,13 @@
 }
 
 /**
+ * An enumeration of lint names.
+ */
+class LintNames {
+  static const String annotate_overrides = 'annotate_overrides';
+}
+
+/**
  * Helper for finding [Element] with name closest to the given.
  */
 class _ClosestElementFinder {
diff --git a/pkg/analysis_server/lib/src/status/get_handler.dart b/pkg/analysis_server/lib/src/status/get_handler.dart
index a65b1610..835488e 100644
--- a/pkg/analysis_server/lib/src/status/get_handler.dart
+++ b/pkg/analysis_server/lib/src/status/get_handler.dart
@@ -646,8 +646,8 @@
           int implicitSourceCount = 0;
           int implicitLineInfoCount = 0;
           int implicitLineCount = 0;
-          analysisServer.folderMap
-              .forEach((Folder folder, InternalAnalysisContext context) {
+          for (InternalAnalysisContext context
+              in analysisServer.analysisContexts) {
             Set<Source> explicitSources = new HashSet<Source>();
             Set<Source> implicitSources = new HashSet<Source>();
             AnalysisCache cache = context.analysisCache;
@@ -708,7 +708,7 @@
             explicitLineCount += lineCount(explicitSources, true);
             implicitSourceCount += implicitSources.length;
             implicitLineCount += lineCount(implicitSources, false);
-          });
+          }
           List<String> sourceTypeNames = sourceTypeCounts.keys.toList();
           sourceTypeNames.sort();
           List<String> typeNames = typeCounts.keys.toList();
@@ -1354,7 +1354,7 @@
           int processorCount = errorProcessors?.length ?? 0;
           buffer.write('<p><b>Error Processor count</b>: $processorCount</p>');
         });
-        
+
         SourceFactory sourceFactory = context.sourceFactory;
         if (sourceFactory is SourceFactoryImpl) {
           buffer.write('<h3>Resolvers</h3>');
diff --git a/pkg/analysis_server/test/analysis/reanalyze_test.dart b/pkg/analysis_server/test/analysis/reanalyze_test.dart
index 0b39e88..b7f62d0 100644
--- a/pkg/analysis_server/test/analysis/reanalyze_test.dart
+++ b/pkg/analysis_server/test/analysis/reanalyze_test.dart
@@ -32,13 +32,13 @@
 
   test_reanalyze() {
     createProject();
-    List<AnalysisContext> contexts = server.folderMap.values.toList();
+    List<AnalysisContext> contexts = server.analysisContexts.toList();
     expect(contexts, hasLength(1));
     AnalysisContext oldContext = contexts[0];
     // Reanalyze should cause a brand new context to be built.
     Request request = new Request("0", ANALYSIS_REANALYZE);
     handleSuccessfulRequest(request);
-    contexts = server.folderMap.values.toList();
+    contexts = server.analysisContexts.toList();
     expect(contexts, hasLength(1));
     AnalysisContext newContext = contexts[0];
     expect(newContext, isNot(same(oldContext)));
diff --git a/pkg/analysis_server/test/analysis_server_test.dart b/pkg/analysis_server/test/analysis_server_test.dart
index e12a691..85a6bbc 100644
--- a/pkg/analysis_server/test/analysis_server_test.dart
+++ b/pkg/analysis_server/test/analysis_server_test.dart
@@ -131,6 +131,9 @@
   }
 
   void setUp() {
+    ExtensionManager manager = new ExtensionManager();
+    ServerPlugin plugin = new ServerPlugin();
+    manager.processPlugins([plugin]);
     channel = new MockServerChannel();
     resourceProvider = new MemoryResourceProvider();
     packageMapProvider = new MockPackageMapProvider();
@@ -139,7 +142,7 @@
         resourceProvider,
         packageMapProvider,
         null,
-        new ServerPlugin(),
+        plugin,
         new AnalysisServerOptions(),
         () => new MockSdk(),
         InstrumentationService.NULL_SERVICE,
diff --git a/pkg/analysis_server/test/context_manager_test.dart b/pkg/analysis_server/test/context_manager_test.dart
index a94314b..1472027 100644
--- a/pkg/analysis_server/test/context_manager_test.dart
+++ b/pkg/analysis_server/test/context_manager_test.dart
@@ -18,6 +18,7 @@
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/source_io.dart';
 import 'package:analyzer/src/services/lint.dart';
+import 'package:analyzer/src/util/glob.dart';
 import 'package:linter/src/plugin/linter_plugin.dart';
 import 'package:linter/src/rules/avoid_as.dart';
 import 'package:package_config/packages.dart';
@@ -92,6 +93,18 @@
     ['x']
   ]);
 
+  List<Glob> get analysisFilesGlobs {
+    List<String> patterns = <String>[
+      '**/*.${AnalysisEngine.SUFFIX_DART}',
+      '**/*.${AnalysisEngine.SUFFIX_HTML}',
+      '**/*.${AnalysisEngine.SUFFIX_HTM}',
+      '**/${AnalysisEngine.ANALYSIS_OPTIONS_FILE}'
+    ];
+    return patterns
+        .map((pattern) => new Glob(JavaFile.pathContext.separator, pattern))
+        .toList();
+  }
+
   List<ErrorProcessor> get errorProcessors => callbacks.currentContext
       .getConfigurationData(CONFIGURED_ERROR_PROCESSORS);
 
@@ -142,7 +155,9 @@
         providePackageResolver,
         provideEmbeddedUriResolver,
         packageMapProvider,
-        InstrumentationService.NULL_SERVICE);
+        analysisFilesGlobs,
+        InstrumentationService.NULL_SERVICE,
+        new AnalysisOptionsImpl());
     callbacks = new TestContextManagerCallbacks(resourceProvider);
     manager.callbacks = callbacks;
     resourceProvider.newFolder(projPath);
@@ -403,8 +418,10 @@
     // * from `.analysis_options`:
     expect(context.analysisOptions.enableGenericMethods, isTrue);
     // * verify tests are excluded
-    expect(callbacks.currentContextFilePaths[projPath].keys,
-        ['/my/proj/sdk_ext/entry.dart']);
+    expect(
+        callbacks.currentContextFilePaths[projPath].keys,
+        unorderedEquals(
+            ['/my/proj/sdk_ext/entry.dart', '/my/proj/.analysis_options']));
 
     // Verify filter setup.
     expect(errorProcessors, hasLength(2));
@@ -656,8 +673,10 @@
         callbacks.currentContextFilePaths[projPath];
     expect(fileTimestamps, isNotEmpty);
     List<String> files = fileTimestamps.keys.toList();
-    expect(files.length, equals(1));
-    expect(files[0], equals('/my/proj/lib/main.dart'));
+    expect(
+        files,
+        unorderedEquals(
+            ['/my/proj/lib/main.dart', '/my/proj/.analysis_options']));
   }
 
   test_path_filter_child_contexts_option() async {
@@ -2363,9 +2382,6 @@
   Iterable<String> get currentContextPaths => currentContextTimestamps.keys;
 
   @override
-  AnalysisOptions get defaultAnalysisOptions => new AnalysisOptionsImpl();
-
-  @override
   AnalysisContext addContext(
       Folder folder, AnalysisOptions options, FolderDisposition disposition) {
     String path = folder.path;
@@ -2429,6 +2445,11 @@
   }
 
   @override
+  void computingPackageMap(bool computing) {
+    // Do nothing.
+  }
+
+  @override
   void removeContext(Folder folder, List<String> flushedFiles) {
     String path = folder.path;
     expect(currentContextPaths, contains(path));
@@ -2439,20 +2460,6 @@
   }
 
   @override
-  bool shouldFileBeAnalyzed(File file) {
-    if (!(AnalysisEngine.isDartFileName(file.path) ||
-        AnalysisEngine.isHtmlFileName(file.path))) {
-      return false;
-    }
-    // Emacs creates dummy links to track the fact that a file is open for
-    // editing and has unsaved changes (e.g. having unsaved changes to
-    // 'foo.dart' causes a link '.#foo.dart' to be created, which points to the
-    // non-existent file 'username@hostname.pid'.  To avoid these dummy links
-    // causing the analyzer to thrash, just ignore links to non-existent files.
-    return file.exists;
-  }
-
-  @override
   void updateContextPackageUriResolver(
       Folder contextFolder, FolderDisposition disposition) {
     currentContextDispositions[contextFolder.path] = disposition;
diff --git a/pkg/analysis_server/test/domain_execution_test.dart b/pkg/analysis_server/test/domain_execution_test.dart
index 1274eab..e6d1dfb 100644
--- a/pkg/analysis_server/test/domain_execution_test.dart
+++ b/pkg/analysis_server/test/domain_execution_test.dart
@@ -223,7 +223,7 @@
       when(manager.isInAnalysisRoot(anyString)).thenReturn(true);
 
       AnalysisServer server = new AnalysisServerMock();
-      when(server.getAnalysisContexts()).thenReturn([context]);
+      when(server.analysisContexts).thenReturn([context]);
       when(server.contextManager).thenReturn(manager);
 
       StreamController controller = new StreamController.broadcast(sync: true);
diff --git a/pkg/analysis_server/test/services/correction/assist_test.dart b/pkg/analysis_server/test/services/correction/assist_test.dart
index 859f248..5c84d35 100644
--- a/pkg/analysis_server/test/services/correction/assist_test.dart
+++ b/pkg/analysis_server/test/services/correction/assist_test.dart
@@ -390,6 +390,15 @@
     await assertNoAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION);
   }
 
+  test_addTypeAnnotation_local_BAD_onInitializer() async {
+    resolveTestUnit('''
+main() {
+  var abc = 0;
+}
+''');
+    await assertNoAssistAt('0;', DartAssistKind.ADD_TYPE_ANNOTATION);
+  }
+
   test_addTypeAnnotation_local_BAD_unknown() async {
     verifyNoTestUnitErrors = false;
     resolveTestUnit('''
@@ -623,22 +632,6 @@
 ''');
   }
 
-  test_addTypeAnnotation_local_OK_onInitializer() async {
-    resolveTestUnit('''
-main() {
-  var v = 123;
-}
-''');
-    await assertHasAssistAt(
-        '23',
-        DartAssistKind.ADD_TYPE_ANNOTATION,
-        '''
-main() {
-  int v = 123;
-}
-''');
-  }
-
   test_addTypeAnnotation_local_OK_onName() async {
     resolveTestUnit('''
 main() {
@@ -671,22 +664,6 @@
 ''');
   }
 
-  test_addTypeAnnotation_local_OK_onVariableDeclarationStatement() async {
-    resolveTestUnit('''
-main() {
-  var v = 123; // marker
-}
-''');
-    await assertHasAssistAt(
-        ' // marker',
-        DartAssistKind.ADD_TYPE_ANNOTATION,
-        '''
-main() {
-  int v = 123; // marker
-}
-''');
-  }
-
   test_addTypeAnnotation_OK_privateType_sameLibrary() async {
     resolveTestUnit('''
 class _A {}
@@ -3283,6 +3260,15 @@
 ''');
   }
 
+  test_removeTypeAnnotation_localVariable_BAD_onInitializer() async {
+    resolveTestUnit('''
+main() {
+  final int v = 1;
+}
+''');
+    await assertNoAssistAt('1;', DartAssistKind.REMOVE_TYPE_ANNOTATION);
+  }
+
   test_removeTypeAnnotation_localVariable_OK() async {
     resolveTestUnit('''
 main() {
@@ -3331,6 +3317,14 @@
 ''');
   }
 
+  test_removeTypeAnnotation_topLevelVariable_BAD_syntheticName() async {
+    verifyNoTestUnitErrors = false;
+    resolveTestUnit('''
+MyType
+''');
+    await assertNoAssistAt('MyType', DartAssistKind.REMOVE_TYPE_ANNOTATION);
+  }
+
   test_removeTypeAnnotation_topLevelVariable_OK() async {
     resolveTestUnit('''
 int V = 1;
diff --git a/pkg/analysis_server/test/services/correction/fix_test.dart b/pkg/analysis_server/test/services/correction/fix_test.dart
index 0d89134..da08e99 100644
--- a/pkg/analysis_server/test/services/correction/fix_test.dart
+++ b/pkg/analysis_server/test/services/correction/fix_test.dart
@@ -27,12 +27,15 @@
 main() {
   initializeTestEnvironment();
   defineReflectiveTests(FixProcessorTest);
+  defineReflectiveTests(LintFixTest);
 }
 
 typedef bool AnalysisErrorFilter(AnalysisError error);
 
-@reflectiveTest
-class FixProcessorTest extends AbstractSingleUnitTest {
+/**
+ * Base class for fix processor tests.
+ */
+class BaseFixProcessorTest extends AbstractSingleUnitTest {
   AnalysisErrorFilter errorFilter = (AnalysisError error) {
     return error.errorCode != HintCode.UNUSED_CATCH_CLAUSE &&
         error.errorCode != HintCode.UNUSED_CATCH_STACK &&
@@ -112,6 +115,80 @@
     verifyNoTestUnitErrors = false;
   }
 
+  /**
+   * Computes fixes and verifies that there is a fix of the given kind.
+   */
+  Future<Fix> _assertHasFix(FixKind kind, AnalysisError error) async {
+    List<Fix> fixes = await _computeFixes(error);
+    for (Fix fix in fixes) {
+      if (fix.kind == kind) {
+        return fix;
+      }
+    }
+    throw fail('Expected to find fix $kind in\n${fixes.join('\n')}');
+  }
+
+  void _assertLinkedGroup(LinkedEditGroup group, List<String> expectedStrings,
+      [List<LinkedEditSuggestion> expectedSuggestions]) {
+    List<Position> expectedPositions = _findResultPositions(expectedStrings);
+    expect(group.positions, unorderedEquals(expectedPositions));
+    if (expectedSuggestions != null) {
+      expect(group.suggestions, unorderedEquals(expectedSuggestions));
+    }
+  }
+
+  /**
+   * Computes fixes for the given [error] in [testUnit].
+   */
+  Future<List<Fix>> _computeFixes(AnalysisError error) async {
+    DartFixContext dartContext = new DartFixContextImpl(
+        new FixContextImpl(provider, context, error), testUnit);
+    FixProcessor processor = new FixProcessor(dartContext);
+    return processor.compute();
+  }
+
+  /**
+   * Configures the [SourceFactory] to have the `my_pkg` package in
+   * `/packages/my_pkg/lib` folder.
+   */
+  void _configureMyPkg(String myLibCode) {
+    provider.newFile('/packages/my_pkg/lib/my_lib.dart', myLibCode);
+    // configure SourceFactory
+    Folder myPkgFolder = provider.getResource('/packages/my_pkg/lib');
+    UriResolver pkgResolver = new PackageMapUriResolver(provider, {
+      'my_pkg': [myPkgFolder]
+    });
+    context.sourceFactory = new SourceFactory(
+        [AbstractContextTest.SDK_RESOLVER, pkgResolver, resourceResolver]);
+    // force 'my_pkg' resolution
+    addSource('/tmp/other.dart', "import 'package:my_pkg/my_lib.dart';");
+  }
+
+  AnalysisError _findErrorToFix() {
+    List<AnalysisError> errors = context.computeErrors(testSource);
+    if (errorFilter != null) {
+      errors = errors.where(errorFilter).toList();
+    }
+    expect(errors, hasLength(1));
+    return errors[0];
+  }
+
+  List<Position> _findResultPositions(List<String> searchStrings) {
+    List<Position> positions = <Position>[];
+    for (String search in searchStrings) {
+      int offset = resultCode.indexOf(search);
+      positions.add(new Position(testFile, offset));
+    }
+    return positions;
+  }
+
+  void _performAnalysis() {
+    while (context.performAnalysisTask().hasMoreWork);
+  }
+}
+
+@reflectiveTest
+class FixProcessorTest extends BaseFixProcessorTest {
   test_addFieldFormalParameters_hasRequiredParameter() async {
     resolveTestUnit('''
 class Test {
@@ -4946,75 +5023,211 @@
 }
 ''');
   }
+}
 
+@reflectiveTest
+class LintFixTest extends BaseFixProcessorTest {
+  AnalysisError error;
+
+  Future applyFix(FixKind kind) async {
+    fix = await _assertHasFix(kind, error);
+    change = fix.change;
+    // apply to "file"
+    List<SourceFileEdit> fileEdits = change.edits;
+    expect(fileEdits, hasLength(1));
+    resultCode = SourceEdit.applySequence(testCode, change.edits[0].edits);
+  }
+
+  void findLint(String src, String lintCode) {
+    int errorOffset = src.indexOf('/*LINT*/');
+    resolveTestUnit(src.replaceAll('/*LINT*/', ''));
+    error = new AnalysisError(testUnit.element.source, errorOffset, 1,
+        new LintCode(lintCode, '<ignored>'));
+  }
+
+  test_lint_addMissingOverride_field() async {
+    String src = '''
+class abstract Test {
+  int get t;
+}
+class Sub extends Test {
+  int /*LINT*/t = 42;
+}
+''';
+    findLint(src, LintNames.annotate_overrides);
+
+    await applyFix(DartFixKind.LINT_ADD_OVERRIDE);
+
+    verifyResult('''
+class abstract Test {
+  int get t;
+}
+class Sub extends Test {
+  @override
+  int t = 42;
+}
+''');
+  }
+
+  test_lint_addMissingOverride_getter() async {
+    String src = '''
+class Test {
+  int get t => null;
+}
+class Sub extends Test {
+  int get /*LINT*/t => null;
+}
+''';
+    findLint(src, LintNames.annotate_overrides);
+
+    await applyFix(DartFixKind.LINT_ADD_OVERRIDE);
+
+    verifyResult('''
+class Test {
+  int get t => null;
+}
+class Sub extends Test {
+  @override
+  int get t => null;
+}
+''');
+  }
+
+  test_lint_addMissingOverride_method() async {
+    String src = '''
+class Test {
+  void t() { }
+}
+class Sub extends Test {
+  void /*LINT*/t() { }
+}
+''';
+    findLint(src, LintNames.annotate_overrides);
+
+    await applyFix(DartFixKind.LINT_ADD_OVERRIDE);
+
+    verifyResult('''
+class Test {
+  void t() { }
+}
+class Sub extends Test {
+  @override
+  void t() { }
+}
+''');
+  }
+
+  test_lint_addMissingOverride_method_with_doc_comment() async {
+    String src = '''
+class Test {
+  void t() { }
+}
+class Sub extends Test {
+  /// Doc comment.
+  void /*LINT*/t() { }
+}
+''';
+    findLint(src, LintNames.annotate_overrides);
+
+    await applyFix(DartFixKind.LINT_ADD_OVERRIDE);
+
+    verifyResult('''
+class Test {
+  void t() { }
+}
+class Sub extends Test {
+  /// Doc comment.
+  @override
+  void t() { }
+}
+''');
+  }
+
+  test_lint_addMissingOverride_method_with_doc_comment_2() async {
+    String src = '''
+class Test {
+  void t() { }
+}
+class Sub extends Test {
   /**
-   * Computes fixes and verifies that there is a fix of the given kind.
+   * Doc comment.
    */
-  Future<Fix> _assertHasFix(FixKind kind, AnalysisError error) async {
-    List<Fix> fixes = await _computeFixes(error);
-    for (Fix fix in fixes) {
-      if (fix.kind == kind) {
-        return fix;
-      }
-    }
-    throw fail('Expected to find fix $kind in\n${fixes.join('\n')}');
-  }
+  void /*LINT*/t() { }
+}
+''';
+    findLint(src, LintNames.annotate_overrides);
 
-  void _assertLinkedGroup(LinkedEditGroup group, List<String> expectedStrings,
-      [List<LinkedEditSuggestion> expectedSuggestions]) {
-    List<Position> expectedPositions = _findResultPositions(expectedStrings);
-    expect(group.positions, unorderedEquals(expectedPositions));
-    if (expectedSuggestions != null) {
-      expect(group.suggestions, unorderedEquals(expectedSuggestions));
-    }
-  }
+    await applyFix(DartFixKind.LINT_ADD_OVERRIDE);
 
+    verifyResult('''
+class Test {
+  void t() { }
+}
+class Sub extends Test {
   /**
-   * Computes fixes for the given [error] in [testUnit].
+   * Doc comment.
    */
-  Future<List<Fix>> _computeFixes(AnalysisError error) async {
-    DartFixContext dartContext = new DartFixContextImpl(
-        new FixContextImpl(provider, context, error), testUnit);
-    FixProcessor processor = new FixProcessor(dartContext);
-    return processor.compute();
+  @override
+  void t() { }
+}
+''');
   }
 
-  /**
-   * Configures the [SourceFactory] to have the `my_pkg` package in
-   * `/packages/my_pkg/lib` folder.
-   */
-  void _configureMyPkg(String myLibCode) {
-    provider.newFile('/packages/my_pkg/lib/my_lib.dart', myLibCode);
-    // configure SourceFactory
-    Folder myPkgFolder = provider.getResource('/packages/my_pkg/lib');
-    UriResolver pkgResolver = new PackageMapUriResolver(provider, {
-      'my_pkg': [myPkgFolder]
-    });
-    context.sourceFactory = new SourceFactory(
-        [AbstractContextTest.SDK_RESOLVER, pkgResolver, resourceResolver]);
-    // force 'my_pkg' resolution
-    addSource('/tmp/other.dart', "import 'package:my_pkg/my_lib.dart';");
+  test_lint_addMissingOverride_method_with_doc_comment_and_metadata() async {
+    String src = '''
+class Test {
+  void t() { }
+}
+class Sub extends Test {
+  /// Doc comment.
+  @foo
+  void /*LINT*/t() { }
+}
+''';
+    findLint(src, LintNames.annotate_overrides);
+
+    await applyFix(DartFixKind.LINT_ADD_OVERRIDE);
+
+    verifyResult('''
+class Test {
+  void t() { }
+}
+class Sub extends Test {
+  /// Doc comment.
+  @override
+  @foo
+  void t() { }
+}
+''');
   }
 
-  AnalysisError _findErrorToFix() {
-    List<AnalysisError> errors = context.computeErrors(testSource);
-    if (errorFilter != null) {
-      errors = errors.where(errorFilter).toList();
-    }
-    expect(errors, hasLength(1));
-    return errors[0];
+  test_lint_addMissingOverride_method_with_non_doc_comment() async {
+    String src = '''
+class Test {
+  void t() { }
+}
+class Sub extends Test {
+  // Non-doc comment.
+  void /*LINT*/t() { }
+}
+''';
+    findLint(src, LintNames.annotate_overrides);
+
+    await applyFix(DartFixKind.LINT_ADD_OVERRIDE);
+
+    verifyResult('''
+class Test {
+  void t() { }
+}
+class Sub extends Test {
+  // Non-doc comment.
+  @override
+  void t() { }
+}
+''');
   }
 
-  List<Position> _findResultPositions(List<String> searchStrings) {
-    List<Position> positions = <Position>[];
-    for (String search in searchStrings) {
-      int offset = resultCode.indexOf(search);
-      positions.add(new Position(testFile, offset));
-    }
-    return positions;
-  }
-
-  void _performAnalysis() {
-    while (context.performAnalysisTask().hasMoreWork);
+  void verifyResult(String expectedResult) {
+    expect(resultCode, expectedResult);
   }
 }
diff --git a/pkg/analyzer/.analysis_options b/pkg/analyzer/.analysis_options
index 7b230dd..7c974bd 100644
--- a/pkg/analyzer/.analysis_options
+++ b/pkg/analyzer/.analysis_options
@@ -1,4 +1,5 @@
 linter:
   rules:
-    - unnecessary_brace_in_string_interp
+    - annotate_overrides
     - empty_constructor_bodies
+    - unnecessary_brace_in_string_interp
diff --git a/pkg/analyzer/example/parser_driver.dart b/pkg/analyzer/example/parser_driver.dart
index c302e41..ccc5bb9 100644
--- a/pkg/analyzer/example/parser_driver.dart
+++ b/pkg/analyzer/example/parser_driver.dart
@@ -43,6 +43,7 @@
 }
 
 class _ASTVisitor extends GeneralizingAstVisitor {
+  @override
   visitNode(AstNode node) {
     print('${node.runtimeType} : <"$node">');
     return super.visitNode(node);
@@ -52,5 +53,6 @@
 class _ErrorCollector extends AnalysisErrorListener {
   List<AnalysisError> errors;
   _ErrorCollector() : errors = new List<AnalysisError>();
+  @override
   onError(error) => errors.add(error);
 }
diff --git a/pkg/analyzer/example/resolver_driver.dart b/pkg/analyzer/example/resolver_driver.dart
index fa2af7f..3ba20f7 100755
--- a/pkg/analyzer/example/resolver_driver.dart
+++ b/pkg/analyzer/example/resolver_driver.dart
@@ -57,6 +57,7 @@
     'Usage: resolve_driver <path_to_sdk> <file_to_resolve> [<packages_root>]';
 
 class _ASTVisitor extends GeneralizingAstVisitor {
+  @override
   visitNode(AstNode node) {
     var lines = <String>['${node.runtimeType} : <"$node">'];
     if (node is SimpleIdentifier) {
diff --git a/pkg/analyzer/lib/analyzer.dart b/pkg/analyzer/lib/analyzer.dart
index 0ac8cf4..fffb006 100644
--- a/pkg/analyzer/lib/analyzer.dart
+++ b/pkg/analyzer/lib/analyzer.dart
@@ -127,5 +127,6 @@
   /// Whether any errors where collected.
   bool get hasErrors => !_errors.isEmpty;
 
+  @override
   void onError(AnalysisError error) => _errors.add(error);
 }
diff --git a/pkg/analyzer/lib/dart/ast/ast.dart b/pkg/analyzer/lib/dart/ast/ast.dart
index 547094b..d0680c4 100644
--- a/pkg/analyzer/lib/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/dart/ast/ast.dart
@@ -53,8 +53,8 @@
  * the same kind (single line or multi-line), this class doesn't enforce that
  * restriction.
  *
- * > adjacentStrings ::=
- * >     [StringLiteral] [StringLiteral]+
+ *    adjacentStrings ::=
+ *        [StringLiteral] [StringLiteral]+
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -110,11 +110,11 @@
 /**
  * An annotation that can be associated with an AST node.
  *
- * > metadata ::=
- * >     annotation*
- * >
- * > annotation ::=
- * >     '@' [Identifier] ('.' [SimpleIdentifier])? [ArgumentList]?
+ *    metadata ::=
+ *        annotation*
+ *
+ *    annotation ::=
+ *        '@' [Identifier] ('.' [SimpleIdentifier])? [ArgumentList]?
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -215,12 +215,12 @@
  * A list of arguments in the invocation of an executable element (that is, a
  * function, method, or constructor).
  *
- * > argumentList ::=
- * >     '(' arguments? ')'
- * >
- * > arguments ::=
- * >     [NamedExpression] (',' [NamedExpression])*
- * >   | [Expression] (',' [Expression])* (',' [NamedExpression])*
+ *    argumentList ::=
+ *        '(' arguments? ')'
+ *
+ *    arguments ::=
+ *        [NamedExpression] (',' [NamedExpression])*
+ *      | [Expression] (',' [Expression])* (',' [NamedExpression])*
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -279,8 +279,8 @@
 /**
  * An as expression.
  *
- * > asExpression ::=
- * >     [Expression] 'as' [TypeName]
+ *    asExpression ::=
+ *        [Expression] 'as' [TypeName]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -326,8 +326,8 @@
 /**
  * An assert statement.
  *
- * > assertStatement ::=
- * >     'assert' '(' [Expression] ')' ';'
+ *    assertStatement ::=
+ *        'assert' '(' [Expression] ')' ';'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -423,8 +423,8 @@
 /**
  * An assignment expression.
  *
- * > assignmentExpression ::=
- * >     [Expression] operator [Expression]
+ *    assignmentExpression ::=
+ *        [Expression] operator [Expression]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -853,8 +853,8 @@
 /**
  * An await expression.
  *
- * > awaitExpression ::=
- * >     'await' [Expression]
+ *    awaitExpression ::=
+ *        'await' [Expression]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -889,8 +889,8 @@
 /**
  * A binary (infix) expression.
  *
- * > binaryExpression ::=
- * >     [Expression] [Token] [Expression]
+ *    binaryExpression ::=
+ *        [Expression] [Token] [Expression]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -975,8 +975,8 @@
 /**
  * A sequence of statements.
  *
- * > block ::=
- * >     '{' statement* '}'
+ *    block ::=
+ *        '{' statement* '}'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -1017,8 +1017,8 @@
 /**
  * A function body that consists of a block of statements.
  *
- * > blockFunctionBody ::=
- * >     ('async' | 'async' '*' | 'sync' '*')? [Block]
+ *    blockFunctionBody ::=
+ *        ('async' | 'async' '*' | 'sync' '*')? [Block]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -1056,8 +1056,8 @@
 /**
  * A boolean literal expression.
  *
- * > booleanLiteral ::=
- * >     'false' | 'true'
+ *    booleanLiteral ::=
+ *        'false' | 'true'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -1086,8 +1086,8 @@
 /**
  * A break statement.
  *
- * > breakStatement ::=
- * >     'break' [SimpleIdentifier]? ';'
+ *    breakStatement ::=
+ *        'break' [SimpleIdentifier]? ';'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -1154,16 +1154,16 @@
  * There are three kinds of expressions that can be used in a cascade
  * expression: [IndexExpression], [MethodInvocation] and [PropertyAccess].
  *
- * > cascadeExpression ::=
- * >     [Expression] cascadeSection*
- * >
- * > cascadeSection ::=
- * >     '..'  (cascadeSelector arguments*) (assignableSelector arguments*)*
- * >     (assignmentOperator expressionWithoutCascade)?
- * >
- * > cascadeSelector ::=
- * >     '[ ' expression '] '
- * >   | identifier
+ *    cascadeExpression ::=
+ *        [Expression] cascadeSection*
+ *
+ *    cascadeSection ::=
+ *        '..'  (cascadeSelector arguments*) (assignableSelector arguments*)*
+ *        (assignmentOperator expressionWithoutCascade)?
+ *
+ *    cascadeSelector ::=
+ *        '[ ' expression '] '
+ *      | identifier
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -1195,12 +1195,12 @@
 /**
  * A catch clause within a try statement.
  *
- * > onPart ::=
- * >     catchPart [Block]
- * >   | 'on' type catchPart? [Block]
- * >
- * > catchPart ::=
- * >     'catch' '(' [SimpleIdentifier] (',' [SimpleIdentifier])? ')'
+ *    onPart ::=
+ *        catchPart [Block]
+ *      | 'on' type catchPart? [Block]
+ *
+ *    catchPart ::=
+ *        'catch' '(' [SimpleIdentifier] (',' [SimpleIdentifier])? ')'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -1326,11 +1326,11 @@
 /**
  * The declaration of a class.
  *
- * > classDeclaration ::=
- * >     'abstract'? 'class' [SimpleIdentifier] [TypeParameterList]?
- * >     ([ExtendsClause] [WithClause]?)?
- * >     [ImplementsClause]?
- * >     '{' [ClassMember]* '}'
+ *    classDeclaration ::=
+ *        'abstract'? 'class' [SimpleIdentifier] [TypeParameterList]?
+ *        ([ExtendsClause] [WithClause]?)?
+ *        [ImplementsClause]?
+ *        '{' [ClassMember]* '}'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -1497,11 +1497,11 @@
 /**
  * A class type alias.
  *
- * > classTypeAlias ::=
- * >     [SimpleIdentifier] [TypeParameterList]? '=' 'abstract'? mixinApplication
- * >
- * > mixinApplication ::=
- * >     [TypeName] [WithClause] [ImplementsClause]? ';'
+ *    classTypeAlias ::=
+ *        [SimpleIdentifier] [TypeParameterList]? '=' 'abstract'? mixinApplication
+ *
+ *    mixinApplication ::=
+ *        [TypeName] [WithClause] [ImplementsClause]? ';'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -1601,9 +1601,9 @@
 /**
  * A combinator associated with an import or export directive.
  *
- * > combinator ::=
- * >     [HideCombinator]
- * >   | [ShowCombinator]
+ *    combinator ::=
+ *        [HideCombinator]
+ *      | [ShowCombinator]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -1624,20 +1624,20 @@
 /**
  * A comment within the source code.
  *
- * > comment ::=
- * >     endOfLineComment
- * >   | blockComment
- * >   | documentationComment
- * >
- * > endOfLineComment ::=
- * >     '//' (CHARACTER - EOL)* EOL
- * >
- * > blockComment ::=
- * >     '/ *' CHARACTER* '&#42;/'
- * >
- * > documentationComment ::=
- * >     '/ **' (CHARACTER | [CommentReference])* '&#42;/'
- * >   | ('///' (CHARACTER - EOL)* EOL)+
+ *    comment ::=
+ *        endOfLineComment
+ *      | blockComment
+ *      | documentationComment
+ *
+ *    endOfLineComment ::=
+ *        '//' (CHARACTER - EOL)* EOL
+ *
+ *    blockComment ::=
+ *        '/ *' CHARACTER* '&#42;/'
+ *
+ *    documentationComment ::=
+ *        '/ **' (CHARACTER | [CommentReference])* '&#42;/'
+ *      | ('///' (CHARACTER - EOL)* EOL)+
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -1706,8 +1706,8 @@
 /**
  * A reference to a Dart element that is found within a documentation comment.
  *
- * > commentReference ::=
- * >     '[' 'new'? [Identifier] ']'
+ *    commentReference ::=
+ *        '[' 'new'? [Identifier] ']'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -1750,19 +1750,19 @@
  * order even if lexical order does not conform to the restrictions of the
  * grammar.
  *
- * > compilationUnit ::=
- * >     directives declarations
- * >
- * > directives ::=
- * >     [ScriptTag]? [LibraryDirective]? namespaceDirective* [PartDirective]*
- * >   | [PartOfDirective]
- * >
- * > namespaceDirective ::=
- * >     [ImportDirective]
- * >   | [ExportDirective]
- * >
- * > declarations ::=
- * >     [CompilationUnitMember]*
+ *    compilationUnit ::=
+ *        directives declarations
+ *
+ *    directives ::=
+ *        [ScriptTag]? [LibraryDirective]? namespaceDirective* [PartDirective]*
+ *      | [PartOfDirective]
+ *
+ *    namespaceDirective ::=
+ *        [ImportDirective]
+ *      | [ExportDirective]
+ *
+ *    declarations ::=
+ *        [CompilationUnitMember]*
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -1848,13 +1848,13 @@
  * A node that declares one or more names within the scope of a compilation
  * unit.
  *
- * > compilationUnitMember ::=
- * >     [ClassDeclaration]
- * >   | [TypeAlias]
- * >   | [FunctionDeclaration]
- * >   | [MethodDeclaration]
- * >   | [VariableDeclaration]
- * >   | [VariableDeclaration]
+ *    compilationUnitMember ::=
+ *        [ClassDeclaration]
+ *      | [TypeAlias]
+ *      | [FunctionDeclaration]
+ *      | [MethodDeclaration]
+ *      | [VariableDeclaration]
+ *      | [VariableDeclaration]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -1863,8 +1863,8 @@
 /**
  * A conditional expression.
  *
- * > conditionalExpression ::=
- * >     [Expression] '?' [Expression] ':' [Expression]
+ *    conditionalExpression ::=
+ *        [Expression] '?' [Expression] ':' [Expression]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -1942,14 +1942,14 @@
 /**
  * A configuration in either an import or export directive.
  *
- * > configuration ::=
- * >     'if' '(' test ')' uri
- * >
- * > test ::=
- * >     dottedName ('==' stringLiteral)?
- * >
- * > dottedName ::=
- * >     identifier ('.' identifier)*
+ *    configuration ::=
+ *        'if' '(' test ')' uri
+ *
+ *    test ::=
+ *        dottedName ('==' stringLiteral)?
+ *
+ *    dottedName ::=
+ *        identifier ('.' identifier)*
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -2047,23 +2047,23 @@
 /**
  * A constructor declaration.
  *
- * > constructorDeclaration ::=
- * >     constructorSignature [FunctionBody]?
- * >   | constructorName formalParameterList ':' 'this' ('.' [SimpleIdentifier])? arguments
- * >
- * > constructorSignature ::=
- * >     'external'? constructorName formalParameterList initializerList?
- * >   | 'external'? 'factory' factoryName formalParameterList initializerList?
- * >   | 'external'? 'const'  constructorName formalParameterList initializerList?
- * >
- * > constructorName ::=
- * >     [SimpleIdentifier] ('.' [SimpleIdentifier])?
- * >
- * > factoryName ::=
- * >     [Identifier] ('.' [SimpleIdentifier])?
- * >
- * > initializerList ::=
- * >     ':' [ConstructorInitializer] (',' [ConstructorInitializer])*
+ *    constructorDeclaration ::=
+ *        constructorSignature [FunctionBody]?
+ *      | constructorName formalParameterList ':' 'this' ('.' [SimpleIdentifier])? arguments
+ *
+ *    constructorSignature ::=
+ *        'external'? constructorName formalParameterList initializerList?
+ *      | 'external'? 'factory' factoryName formalParameterList initializerList?
+ *      | 'external'? 'const'  constructorName formalParameterList initializerList?
+ *
+ *    constructorName ::=
+ *        [SimpleIdentifier] ('.' [SimpleIdentifier])?
+ *
+ *    factoryName ::=
+ *        [Identifier] ('.' [SimpleIdentifier])?
+ *
+ *    initializerList ::=
+ *        ':' [ConstructorInitializer] (',' [ConstructorInitializer])*
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -2229,8 +2229,8 @@
 /**
  * The initialization of a field within a constructor's initialization list.
  *
- * > fieldInitializer ::=
- * >     ('this' '.')? [SimpleIdentifier] '=' [Expression]
+ *    fieldInitializer ::=
+ *        ('this' '.')? [SimpleIdentifier] '=' [Expression]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -2307,10 +2307,10 @@
 /**
  * A node that can occur in the initializer list of a constructor declaration.
  *
- * > constructorInitializer ::=
- * >     [SuperConstructorInvocation]
- * >   | [ConstructorFieldInitializer]
- * >   | [RedirectingConstructorInvocation]
+ *    constructorInitializer ::=
+ *        [SuperConstructorInvocation]
+ *      | [ConstructorFieldInitializer]
+ *      | [RedirectingConstructorInvocation]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -2319,8 +2319,8 @@
 /**
  * The name of a constructor.
  *
- * > constructorName ::=
- * >     type ('.' identifier)?
+ *    constructorName ::=
+ *        type ('.' identifier)?
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -2382,8 +2382,8 @@
 /**
  * A continue statement.
  *
- * > continueStatement ::=
- * >     'continue' [SimpleIdentifier]? ';'
+ *    continueStatement ::=
+ *        'continue' [SimpleIdentifier]? ';'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -2462,8 +2462,8 @@
 /**
  * The declaration of a single identifier.
  *
- * > declaredIdentifier ::=
- * >     [Annotation] finalConstVarOrType [SimpleIdentifier]
+ *    declaredIdentifier ::=
+ *        [Annotation] finalConstVarOrType [SimpleIdentifier]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -2535,11 +2535,11 @@
  * that are both represented by this class: named formal parameters and
  * positional formal parameters.
  *
- * > defaultFormalParameter ::=
- * >     [NormalFormalParameter] ('=' [Expression])?
- * >
- * > defaultNamedParameter ::=
- * >     [NormalFormalParameter] (':' [Expression])?
+ *    defaultFormalParameter ::=
+ *        [NormalFormalParameter] ('=' [Expression])?
+ *
+ *    defaultNamedParameter ::=
+ *        [NormalFormalParameter] (':' [Expression])?
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -2598,12 +2598,12 @@
 /**
  * A node that represents a directive.
  *
- * > directive ::=
- * >     [ExportDirective]
- * >   | [ImportDirective]
- * >   | [LibraryDirective]
- * >   | [PartDirective]
- * >   | [PartOfDirective]
+ *    directive ::=
+ *        [ExportDirective]
+ *      | [ImportDirective]
+ *      | [LibraryDirective]
+ *      | [PartDirective]
+ *      | [PartOfDirective]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -2629,8 +2629,8 @@
 /**
  * A do statement.
  *
- * > doStatement ::=
- * >     'do' [Statement] 'while' '(' [Expression] ')' ';'
+ *    doStatement ::=
+ *        'do' [Statement] 'while' '(' [Expression] ')' ';'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -2722,8 +2722,8 @@
 /**
  * A dotted name, used in a configuration within an import or export directive.
  *
- * > dottedName ::=
- * >     [SimpleIdentifier] ('.' [SimpleIdentifier])*
+ *    dottedName ::=
+ *        [SimpleIdentifier] ('.' [SimpleIdentifier])*
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -2742,12 +2742,12 @@
 /**
  * A floating point literal expression.
  *
- * > doubleLiteral ::=
- * >     decimalDigit+ ('.' decimalDigit*)? exponent?
- * >   | '.' decimalDigit+ exponent?
- * >
- * > exponent ::=
- * >     ('e' | 'E') ('+' | '-')? decimalDigit+
+ *    doubleLiteral ::=
+ *        decimalDigit+ ('.' decimalDigit*)? exponent?
+ *      | '.' decimalDigit+ exponent?
+ *
+ *    exponent ::=
+ *        ('e' | 'E') ('+' | '-')? decimalDigit+
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -2782,8 +2782,8 @@
  * An empty function body, which can only appear in constructors or abstract
  * methods.
  *
- * > emptyFunctionBody ::=
- * >     ';'
+ *    emptyFunctionBody ::=
+ *        ';'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -2809,8 +2809,8 @@
 /**
  * An empty statement.
  *
- * > emptyStatement ::=
- * >     ';'
+ *    emptyStatement ::=
+ *        ';'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -2861,8 +2861,8 @@
 /**
  * The declaration of an enumeration.
  *
- * > enumType ::=
- * >     metadata 'enum' [SimpleIdentifier] '{' [SimpleIdentifier] (',' [SimpleIdentifier])* (',')? '}'
+ *    enumType ::=
+ *        metadata 'enum' [SimpleIdentifier] '{' [SimpleIdentifier] (',' [SimpleIdentifier])* (',')? '}'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -2924,8 +2924,8 @@
 /**
  * An export directive.
  *
- * > exportDirective ::=
- * >     [Annotation] 'export' [StringLiteral] [Combinator]* ';'
+ *    exportDirective ::=
+ *        [Annotation] 'export' [StringLiteral] [Combinator]* ';'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -2949,10 +2949,10 @@
 /**
  * A node that represents an expression.
  *
- * > expression ::=
- * >     [AssignmentExpression]
- * >   | [ConditionalExpression] cascadeSection*
- * >   | [ThrowExpression]
+ *    expression ::=
+ *        [AssignmentExpression]
+ *      | [ConditionalExpression] cascadeSection*
+ *      | [ThrowExpression]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -3043,8 +3043,8 @@
 /**
  * A function body consisting of a single expression.
  *
- * > expressionFunctionBody ::=
- * >     'async'? '=>' [Expression] ';'
+ *    expressionFunctionBody ::=
+ *        'async'? '=>' [Expression] ';'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -3099,8 +3099,8 @@
 /**
  * An expression used as a statement.
  *
- * > expressionStatement ::=
- * >     [Expression]? ';'
+ *    expressionStatement ::=
+ *        [Expression]? ';'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -3136,8 +3136,8 @@
 /**
  * The "extends" clause in a class declaration.
  *
- * > extendsClause ::=
- * >     'extends' [TypeName]
+ *    extendsClause ::=
+ *        'extends' [TypeName]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -3172,8 +3172,8 @@
 /**
  * The declaration of one or more fields of the same type.
  *
- * > fieldDeclaration ::=
- * >     'static'? [VariableDeclarationList] ';'
+ *    fieldDeclaration ::=
+ *        'static'? [VariableDeclarationList] ';'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -3231,9 +3231,9 @@
 /**
  * A field formal parameter.
  *
- * > fieldFormalParameter ::=
- * >     ('final' [TypeName] | 'const' [TypeName] | 'var' | [TypeName])?
- * >     'this' '.' [SimpleIdentifier] ([TypeParameterList]? [FormalParameterList])?
+ *    fieldFormalParameter ::=
+ *        ('final' [TypeName] | 'const' [TypeName] | 'var' | [TypeName])?
+ *        'this' '.' [SimpleIdentifier] ([TypeParameterList]? [FormalParameterList])?
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -3331,9 +3331,9 @@
 /**
  * A for-each statement.
  *
- * > forEachStatement ::=
- * >     'await'? 'for' '(' [DeclaredIdentifier] 'in' [Expression] ')' [Block]
- * >   | 'await'? 'for' '(' [SimpleIdentifier] 'in' [Expression] ')' [Block]
+ *    forEachStatement ::=
+ *        'await'? 'for' '(' [DeclaredIdentifier] 'in' [Expression] ')' [Block]
+ *      | 'await'? 'for' '(' [SimpleIdentifier] 'in' [Expression] ')' [Block]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -3466,9 +3466,9 @@
 /**
  * A node representing a parameter to a function.
  *
- * > formalParameter ::=
- * >     [NormalFormalParameter]
- * >   | [DefaultFormalParameter]
+ *    formalParameter ::=
+ *        [NormalFormalParameter]
+ *      | [DefaultFormalParameter]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -3517,23 +3517,23 @@
  * flattened into a single list, which can have any or all kinds of parameters
  * (normal, named, and positional) in any order.
  *
- * > formalParameterList ::=
- * >     '(' ')'
- * >   | '(' normalFormalParameters (',' optionalFormalParameters)? ')'
- * >   | '(' optionalFormalParameters ')'
- * >
- * > normalFormalParameters ::=
- * >     [NormalFormalParameter] (',' [NormalFormalParameter])*
- * >
- * > optionalFormalParameters ::=
- * >     optionalPositionalFormalParameters
- * >   | namedFormalParameters
- * >
- * > optionalPositionalFormalParameters ::=
- * >     '[' [DefaultFormalParameter] (',' [DefaultFormalParameter])* ']'
- * >
- * > namedFormalParameters ::=
- * >     '{' [DefaultFormalParameter] (',' [DefaultFormalParameter])* '}'
+ *    formalParameterList ::=
+ *        '(' ')'
+ *      | '(' normalFormalParameters (',' optionalFormalParameters)? ')'
+ *      | '(' optionalFormalParameters ')'
+ *
+ *    normalFormalParameters ::=
+ *        [NormalFormalParameter] (',' [NormalFormalParameter])*
+ *
+ *    optionalFormalParameters ::=
+ *        optionalPositionalFormalParameters
+ *      | namedFormalParameters
+ *
+ *    optionalPositionalFormalParameters ::=
+ *        '[' [DefaultFormalParameter] (',' [DefaultFormalParameter])* ']'
+ *
+ *    namedFormalParameters ::=
+ *        '{' [DefaultFormalParameter] (',' [DefaultFormalParameter])* '}'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -3610,15 +3610,15 @@
 /**
  * A for statement.
  *
- * > forStatement ::=
- * >     'for' '(' forLoopParts ')' [Statement]
- * >
- * > forLoopParts ::=
- * >     forInitializerStatement ';' [Expression]? ';' [Expression]?
- * >
- * > forInitializerStatement ::=
- * >     [DefaultFormalParameter]
- * >   | [Expression]?
+ *    forStatement ::=
+ *        'for' '(' forLoopParts ')' [Statement]
+ *
+ *    forLoopParts ::=
+ *        forInitializerStatement ';' [Expression]? ';' [Expression]?
+ *
+ *    forInitializerStatement ::=
+ *        [DefaultFormalParameter]
+ *      | [Expression]?
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -3746,10 +3746,10 @@
 /**
  * A node representing the body of a function or method.
  *
- * > functionBody ::=
- * >     [BlockFunctionBody]
- * >   | [EmptyFunctionBody]
- * >   | [ExpressionFunctionBody]
+ *    functionBody ::=
+ *        [BlockFunctionBody]
+ *      | [EmptyFunctionBody]
+ *      | [ExpressionFunctionBody]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -3811,12 +3811,12 @@
 /**
  * A top-level declaration.
  *
- * > functionDeclaration ::=
- * >     'external' functionSignature
- * >   | functionSignature [FunctionBody]
- * >
- * > functionSignature ::=
- * >     [Type]? ('get' | 'set')? [SimpleIdentifier] [FormalParameterList]
+ *    functionDeclaration ::=
+ *        'external' functionSignature
+ *      | functionSignature [FunctionBody]
+ *
+ *    functionSignature ::=
+ *        [Type]? ('get' | 'set')? [SimpleIdentifier] [FormalParameterList]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -3924,8 +3924,8 @@
 /**
  * A function expression.
  *
- * > functionExpression ::=
- * >     [TypeParameterList]? [FormalParameterList] [FunctionBody]
+ *    functionExpression ::=
+ *        [TypeParameterList]? [FormalParameterList] [FunctionBody]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -3989,8 +3989,8 @@
  * [MethodInvocation] nodes. Invocations of getters and setters are represented
  * by either [PrefixedIdentifier] or [PropertyAccess] nodes.
  *
- * > functionExpressionInvocation ::=
- * >     [Expression] [TypeArgumentList]? [ArgumentList]
+ *    functionExpressionInvocation ::=
+ *        [Expression] [TypeArgumentList]? [ArgumentList]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -4020,6 +4020,7 @@
   /**
    * Return the expression producing the function being invoked.
    */
+  @override
   Expression get function;
 
   /**
@@ -4050,12 +4051,14 @@
    * [InterfaceType] with a `call` method, `dynamic`, `Function`, or a `@proxy`
    * interface type that implements `Function`.
    */
+  @override
   DartType get propagatedInvokeType;
 
   /**
    * Set the function type of the method invocation based on the propagated type
    * information to the given [type].
    */
+  @override
   void set propagatedInvokeType(DartType type);
 
   /**
@@ -4080,12 +4083,14 @@
    * [InterfaceType] with a `call` method, `dynamic`, `Function`, or a `@proxy`
    * interface type that implements `Function`.
    */
+  @override
   DartType get staticInvokeType;
 
   /**
    * Set the function type of the method invocation based on the static type
    * information to the given [type].
    */
+  @override
   void set staticInvokeType(DartType type);
 
   /**
@@ -4098,11 +4103,11 @@
 /**
  * A function type alias.
  *
- * > functionTypeAlias ::=
- * >     functionPrefix [TypeParameterList]? [FormalParameterList] ';'
- * >
- * > functionPrefix ::=
- * >     [TypeName]? [SimpleIdentifier]
+ *    functionTypeAlias ::=
+ *        functionPrefix [TypeParameterList]? [FormalParameterList] ';'
+ *
+ *    functionPrefix ::=
+ *        [TypeName]? [SimpleIdentifier]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -4163,8 +4168,8 @@
 /**
  * A function-typed formal parameter.
  *
- * > functionSignature ::=
- * >     [TypeName]? [SimpleIdentifier] [TypeParameterList]? [FormalParameterList]
+ *    functionSignature ::=
+ *        [TypeName]? [SimpleIdentifier] [TypeParameterList]? [FormalParameterList]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -4222,8 +4227,8 @@
  * A combinator that restricts the names being imported to those that are not in
  * a given list.
  *
- * > hideCombinator ::=
- * >     'hide' [SimpleIdentifier] (',' [SimpleIdentifier])*
+ *    hideCombinator ::=
+ *        'hide' [SimpleIdentifier] (',' [SimpleIdentifier])*
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -4244,9 +4249,9 @@
 /**
  * A node that represents an identifier.
  *
- * > identifier ::=
- * >     [SimpleIdentifier]
- * >   | [PrefixedIdentifier]
+ *    identifier ::=
+ *        [SimpleIdentifier]
+ *      | [PrefixedIdentifier]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -4292,8 +4297,8 @@
 /**
  * An if statement.
  *
- * > ifStatement ::=
- * >     'if' '(' [Expression] ')' [Statement] ('else' [Statement])?
+ *    ifStatement ::=
+ *        'if' '(' [Expression] ')' [Statement] ('else' [Statement])?
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -4391,8 +4396,8 @@
 /**
  * The "implements" clause in an class declaration.
  *
- * > implementsClause ::=
- * >     'implements' [TypeName] (',' [TypeName])*
+ *    implementsClause ::=
+ *        'implements' [TypeName] (',' [TypeName])*
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -4422,9 +4427,9 @@
 /**
  * An import directive.
  *
- * > importDirective ::=
- * >     [Annotation] 'import' [StringLiteral] ('as' identifier)? [Combinator]* ';'
- * >   | [Annotation] 'import' [StringLiteral] 'deferred' 'as' identifier [Combinator]* ';'
+ *    importDirective ::=
+ *        [Annotation] 'import' [StringLiteral] ('as' identifier)? [Combinator]* ';'
+ *      | [Annotation] 'import' [StringLiteral] 'deferred' 'as' identifier [Combinator]* ';'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -4580,8 +4585,8 @@
 /**
  * An index expression.
  *
- * > indexExpression ::=
- * >     [Expression] '[' [Expression] ']'
+ *    indexExpression ::=
+ *        [Expression] '[' [Expression] ']'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -4744,8 +4749,8 @@
 /**
  * An instance creation expression.
  *
- * > newExpression ::=
- * >     ('new' | 'const') [TypeName] ('.' [SimpleIdentifier])? [ArgumentList]
+ *    newExpression ::=
+ *        ('new' | 'const') [TypeName] ('.' [SimpleIdentifier])? [ArgumentList]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -4813,16 +4818,16 @@
 /**
  * An integer literal expression.
  *
- * > integerLiteral ::=
- * >     decimalIntegerLiteral
- * >   | hexadecimalIntegerLiteral
- * >
- * > decimalIntegerLiteral ::=
- * >     decimalDigit+
- * >
- * > hexadecimalIntegerLiteral ::=
- * >     '0x' hexadecimalDigit+
- * >   | '0X' hexadecimalDigit+
+ *    integerLiteral ::=
+ *        decimalIntegerLiteral
+ *      | hexadecimalIntegerLiteral
+ *
+ *    decimalIntegerLiteral ::=
+ *        decimalDigit+
+ *
+ *    hexadecimalIntegerLiteral ::=
+ *        '0x' hexadecimalDigit+
+ *      | '0X' hexadecimalDigit+
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -4856,9 +4861,9 @@
 /**
  * A node within a [StringInterpolation].
  *
- * > interpolationElement ::=
- * >     [InterpolationExpression]
- * >   | [InterpolationString]
+ *    interpolationElement ::=
+ *        [InterpolationExpression]
+ *      | [InterpolationString]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -4867,9 +4872,9 @@
 /**
  * An expression embedded in a string interpolation.
  *
- * > interpolationExpression ::=
- * >     '$' [SimpleIdentifier]
- * >   | '$' '{' [Expression] '}'
+ *    interpolationExpression ::=
+ *        '$' [SimpleIdentifier]
+ *      | '$' '{' [Expression] '}'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -4922,8 +4927,8 @@
 /**
  * A non-empty substring of an interpolated string.
  *
- * > interpolationString ::=
- * >     characters
+ *    interpolationString ::=
+ *        characters
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -5036,8 +5041,8 @@
 /**
  * An is expression.
  *
- * > isExpression ::=
- * >     [Expression] 'is' '!'? [TypeName]
+ *    isExpression ::=
+ *        [Expression] 'is' '!'? [TypeName]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -5094,8 +5099,8 @@
 /**
  * A label on either a [LabeledStatement] or a [NamedExpression].
  *
- * > label ::=
- * >     [SimpleIdentifier] ':'
+ *    label ::=
+ *        [SimpleIdentifier] ':'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -5130,8 +5135,8 @@
 /**
  * A statement that has a label associated with them.
  *
- * > labeledStatement ::=
- * >    [Label]+ [Statement]
+ *    labeledStatement ::=
+ *       [Label]+ [Statement]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -5162,8 +5167,8 @@
 /**
  * A library directive.
  *
- * > libraryDirective ::=
- * >     [Annotation] 'library' [Identifier] ';'
+ *    libraryDirective ::=
+ *        [Annotation] 'library' [Identifier] ';'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -5214,8 +5219,8 @@
 /**
  * The identifier for a library.
  *
- * > libraryIdentifier ::=
- * >     [SimpleIdentifier] ('.' [SimpleIdentifier])*
+ *    libraryIdentifier ::=
+ *        [SimpleIdentifier] ('.' [SimpleIdentifier])*
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -5235,8 +5240,8 @@
 /**
  * A list literal.
  *
- * > listLiteral ::=
- * >     'const'? ('<' [TypeName] '>')? '[' ([Expression] ','?)? ']'
+ *    listLiteral ::=
+ *        'const'? ('<' [TypeName] '>')? '[' ([Expression] ','?)? ']'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -5283,14 +5288,14 @@
 /**
  * A node that represents a literal expression.
  *
- * > literal ::=
- * >     [BooleanLiteral]
- * >   | [DoubleLiteral]
- * >   | [IntegerLiteral]
- * >   | [ListLiteral]
- * >   | [MapLiteral]
- * >   | [NullLiteral]
- * >   | [StringLiteral]
+ *    literal ::=
+ *        [BooleanLiteral]
+ *      | [DoubleLiteral]
+ *      | [IntegerLiteral]
+ *      | [ListLiteral]
+ *      | [MapLiteral]
+ *      | [NullLiteral]
+ *      | [StringLiteral]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -5299,9 +5304,9 @@
 /**
  * A literal map.
  *
- * > mapLiteral ::=
- * >     'const'? ('<' [TypeName] (',' [TypeName])* '>')?
- * >     '{' ([MapLiteralEntry] (',' [MapLiteralEntry])* ','?)? '}'
+ *    mapLiteral ::=
+ *        'const'? ('<' [TypeName] (',' [TypeName])* '>')?
+ *        '{' ([MapLiteralEntry] (',' [MapLiteralEntry])* ','?)? '}'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -5347,8 +5352,8 @@
 /**
  * A single key/value pair in a map literal.
  *
- * > mapLiteralEntry ::=
- * >     [Expression] ':' [Expression]
+ *    mapLiteralEntry ::=
+ *        [Expression] ':' [Expression]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -5397,16 +5402,16 @@
 /**
  * A method declaration.
  *
- * > methodDeclaration ::=
- * >     methodSignature [FunctionBody]
- * >
- * > methodSignature ::=
- * >     'external'? ('abstract' | 'static')? [Type]? ('get' | 'set')?
- * >     methodName [TypeParameterList] [FormalParameterList]
- * >
- * > methodName ::=
- * >     [SimpleIdentifier]
- * >   | 'operator' [SimpleIdentifier]
+ *    methodDeclaration ::=
+ *        methodSignature [FunctionBody]
+ *
+ *    methodSignature ::=
+ *        'external'? ('abstract' | 'static')? [Type]? ('get' | 'set')?
+ *        methodName [TypeParameterList] [FormalParameterList]
+ *
+ *    methodName ::=
+ *        [SimpleIdentifier]
+ *      | 'operator' [SimpleIdentifier]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -5570,8 +5575,8 @@
  * [FunctionExpressionInvocation] nodes. Invocations of getters and setters are
  * represented by either [PrefixedIdentifier] or [PropertyAccess] nodes.
  *
- * > methodInvocation ::=
- * >     ([Expression] '.')? [SimpleIdentifier] [TypeArgumentList]? [ArgumentList]
+ *    methodInvocation ::=
+ *        ([Expression] '.')? [SimpleIdentifier] [TypeArgumentList]? [ArgumentList]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -5632,12 +5637,14 @@
    * [InterfaceType] with a `call` method, `dynamic`, `Function`, or a `@proxy`
    * interface type that implements `Function`.
    */
+  @override
   DartType get propagatedInvokeType;
 
   /**
    * Set the function type of the method invocation based on the propagated type
    * information to the given [type].
    */
+  @override
   void set propagatedInvokeType(DartType type);
 
   /**
@@ -5657,12 +5664,14 @@
    * [InterfaceType] with a `call` method, `dynamic`, `Function`, or a `@proxy`
    * interface type that implements `Function`.
    */
+  @override
   DartType get staticInvokeType;
 
   /**
    * Set the function type of the method invocation based on the static type
    * information to the given [type].
    */
+  @override
   void set staticInvokeType(DartType type);
 
   /**
@@ -5709,8 +5718,8 @@
  * An expression that has a name associated with it. They are used in method
  * invocations when there are named parameters.
  *
- * > namedExpression ::=
- * >     [Label] [Expression]
+ *    namedExpression ::=
+ *        [Label] [Expression]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -5753,9 +5762,9 @@
 /**
  * A node that represents a directive that impacts the namespace of a library.
  *
- * > directive ::=
- * >     [ExportDirective]
- * >   | [ImportDirective]
+ *    directive ::=
+ *        [ExportDirective]
+ *      | [ImportDirective]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -5791,8 +5800,8 @@
 /**
  * The "native" clause in an class declaration.
  *
- * > nativeClause ::=
- * >     'native' [StringLiteral]
+ *    nativeClause ::=
+ *        'native' [StringLiteral]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -5829,8 +5838,8 @@
  * A function body that consists of a native keyword followed by a string
  * literal.
  *
- * > nativeFunctionBody ::=
- * >     'native' [SimpleStringLiteral] ';'
+ *    nativeFunctionBody ::=
+ *        'native' [SimpleStringLiteral] ';'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -5920,12 +5929,14 @@
    * Return the node at the given [index] in the list or throw a [RangeError] if
    * [index] is out of bounds.
    */
+  @override
   E operator [](int index);
 
   /**
    * Set the node at the given [index] in the list to the given [node] or throw
    * a [RangeError] if [index] is out of bounds.
    */
+  @override
   void operator []=(int index, E node);
 
   /**
@@ -5937,10 +5948,10 @@
 /**
  * A formal parameter that is required (is not optional).
  *
- * > normalFormalParameter ::=
- * >     [FunctionTypedFormalParameter]
- * >   | [FieldFormalParameter]
- * >   | [SimpleFormalParameter]
+ *    normalFormalParameter ::=
+ *        [FunctionTypedFormalParameter]
+ *      | [FieldFormalParameter]
+ *      | [SimpleFormalParameter]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -5977,8 +5988,8 @@
 /**
  * A null literal expression.
  *
- * > nullLiteral ::=
- * >     'null'
+ *    nullLiteral ::=
+ *        'null'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -6002,8 +6013,8 @@
 /**
  * A parenthesized expression.
  *
- * > parenthesizedExpression ::=
- * >     '(' [Expression] ')'
+ *    parenthesizedExpression ::=
+ *        '(' [Expression] ')'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -6048,8 +6059,8 @@
 /**
  * A part directive.
  *
- * > partDirective ::=
- * >     [Annotation] 'part' [StringLiteral] ';'
+ *    partDirective ::=
+ *        [Annotation] 'part' [StringLiteral] ';'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -6090,8 +6101,8 @@
 /**
  * A part-of directive.
  *
- * > partOfDirective ::=
- * >     [Annotation] 'part' 'of' [Identifier] ';'
+ *    partOfDirective ::=
+ *        [Annotation] 'part' 'of' [Identifier] ';'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -6155,8 +6166,8 @@
 /**
  * A postfix unary expression.
  *
- * > postfixExpression ::=
- * >     [Expression] [Token]
+ *    postfixExpression ::=
+ *        [Expression] [Token]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -6229,8 +6240,8 @@
  * An identifier that is prefixed or an access to an object property where the
  * target of the property access is a simple identifier.
  *
- * > prefixedIdentifier ::=
- * >     [SimpleIdentifier] '.' [SimpleIdentifier]
+ *    prefixedIdentifier ::=
+ *        [SimpleIdentifier] '.' [SimpleIdentifier]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -6288,8 +6299,8 @@
 /**
  * A prefix unary expression.
  *
- * > prefixExpression ::=
- * >     [Token] [Expression]
+ *    prefixExpression ::=
+ *        [Token] [Expression]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -6365,8 +6376,8 @@
  * as [PrefixedIdentifier] nodes in cases where the target is also a simple
  * identifier.
  *
- * > propertyAccess ::=
- * >     [Expression] '.' [SimpleIdentifier]
+ *    propertyAccess ::=
+ *        [Expression] '.' [SimpleIdentifier]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -6433,8 +6444,8 @@
  * The invocation of a constructor in the same class from within a constructor's
  * initialization list.
  *
- * > redirectingConstructorInvocation ::=
- * >     'this' ('.' identifier)? arguments
+ *    redirectingConstructorInvocation ::=
+ *        'this' ('.' identifier)? arguments
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -6511,8 +6522,8 @@
 /**
  * A rethrow expression.
  *
- * > rethrowExpression ::=
- * >     'rethrow'
+ *    rethrowExpression ::=
+ *        'rethrow'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -6536,8 +6547,8 @@
 /**
  * A return statement.
  *
- * > returnStatement ::=
- * >     'return' [Expression]? ';'
+ *    returnStatement ::=
+ *        'return' [Expression]? ';'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -6586,8 +6597,8 @@
 /**
  * A script tag that can optionally occur at the beginning of a compilation unit.
  *
- * > scriptTag ::=
- * >     '#!' (~NEWLINE)* NEWLINE
+ *    scriptTag ::=
+ *        '#!' (~NEWLINE)* NEWLINE
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -6611,8 +6622,8 @@
 /**
  * A combinator that restricts the names being imported to those in a given list.
  *
- * > showCombinator ::=
- * >     'show' [SimpleIdentifier] (',' [SimpleIdentifier])*
+ *    showCombinator ::=
+ *        'show' [SimpleIdentifier] (',' [SimpleIdentifier])*
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -6633,8 +6644,8 @@
 /**
  * A simple formal parameter.
  *
- * > simpleFormalParameter ::=
- * >     ('final' [TypeName] | 'var' | [TypeName])? [SimpleIdentifier]
+ *    simpleFormalParameter ::=
+ *        ('final' [TypeName] | 'var' | [TypeName])? [SimpleIdentifier]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -6679,12 +6690,12 @@
 /**
  * A simple identifier.
  *
- * > simpleIdentifier ::=
- * >     initialCharacter internalCharacter*
- * >
- * > initialCharacter ::= '_' | '$' | letter
- * >
- * > internalCharacter ::= '_' | '$' | letter | digit
+ *    simpleIdentifier ::=
+ *        initialCharacter internalCharacter*
+ *
+ *    initialCharacter ::= '_' | '$' | letter
+ *
+ *    internalCharacter ::= '_' | '$' | letter | digit
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -6769,24 +6780,24 @@
 /**
  * A string literal expression that does not contain any interpolations.
  *
- * > simpleStringLiteral ::=
- * >     rawStringLiteral
- * >   | basicStringLiteral
- * >
- * > rawStringLiteral ::=
- * >     'r' basicStringLiteral
- * >
- * > simpleStringLiteral ::=
- * >     multiLineStringLiteral
- * >   | singleLineStringLiteral
- * >
- * > multiLineStringLiteral ::=
- * >     "'''" characters "'''"
- * >   | '"""' characters '"""'
- * >
- * > singleLineStringLiteral ::=
- * >     "'" characters "'"
- * >   | '"' characters '"'
+ *    simpleStringLiteral ::=
+ *        rawStringLiteral
+ *      | basicStringLiteral
+ *
+ *    rawStringLiteral ::=
+ *        'r' basicStringLiteral
+ *
+ *    simpleStringLiteral ::=
+ *        multiLineStringLiteral
+ *      | singleLineStringLiteral
+ *
+ *    multiLineStringLiteral ::=
+ *        "'''" characters "'''"
+ *      | '"""' characters '"""'
+ *
+ *    singleLineStringLiteral ::=
+ *        "'" characters "'"
+ *      | '"' characters '"'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -6821,9 +6832,9 @@
 /**
  * A single string literal expression.
  *
- * > singleStringLiteral ::=
- * >     [SimpleStringLiteral]
- * >   | [StringInterpolation]
+ *    singleStringLiteral ::=
+ *        [SimpleStringLiteral]
+ *      | [StringInterpolation]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -6859,21 +6870,21 @@
 /**
  * A node that represents a statement.
  *
- * > statement ::=
- * >     [Block]
- * >   | [VariableDeclarationStatement]
- * >   | [ForStatement]
- * >   | [ForEachStatement]
- * >   | [WhileStatement]
- * >   | [DoStatement]
- * >   | [SwitchStatement]
- * >   | [IfStatement]
- * >   | [TryStatement]
- * >   | [BreakStatement]
- * >   | [ContinueStatement]
- * >   | [ReturnStatement]
- * >   | [ExpressionStatement]
- * >   | [FunctionDeclarationStatement]
+ *    statement ::=
+ *        [Block]
+ *      | [VariableDeclarationStatement]
+ *      | [ForStatement]
+ *      | [ForEachStatement]
+ *      | [WhileStatement]
+ *      | [DoStatement]
+ *      | [SwitchStatement]
+ *      | [IfStatement]
+ *      | [TryStatement]
+ *      | [BreakStatement]
+ *      | [ContinueStatement]
+ *      | [ReturnStatement]
+ *      | [ExpressionStatement]
+ *      | [FunctionDeclarationStatement]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -6888,9 +6899,9 @@
 /**
  * A string interpolation literal.
  *
- * > stringInterpolation ::=
- * >     ''' [InterpolationElement]* '''
- * >   | '"' [InterpolationElement]* '"'
+ *    stringInterpolation ::=
+ *        ''' [InterpolationElement]* '''
+ *      | '"' [InterpolationElement]* '"'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -6910,10 +6921,10 @@
 /**
  * A string literal expression.
  *
- * > stringLiteral ::=
- * >     [SimpleStringLiteral]
- * >   | [AdjacentStrings]
- * >   | [StringInterpolation]
+ *    stringLiteral ::=
+ *        [SimpleStringLiteral]
+ *      | [AdjacentStrings]
+ *      | [StringInterpolation]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -6929,8 +6940,8 @@
  * The invocation of a superclass' constructor from within a constructor's
  * initialization list.
  *
- * > superInvocation ::=
- * >     'super' ('.' [SimpleIdentifier])? [ArgumentList]
+ *    superInvocation ::=
+ *        'super' ('.' [SimpleIdentifier])? [ArgumentList]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -7008,8 +7019,8 @@
 /**
  * A super expression.
  *
- * > superExpression ::=
- * >     'super'
+ *    superExpression ::=
+ *        'super'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -7033,8 +7044,8 @@
 /**
  * A case in a switch statement.
  *
- * > switchCase ::=
- * >     [SimpleIdentifier]* 'case' [Expression] ':' [Statement]*
+ *    switchCase ::=
+ *        [SimpleIdentifier]* 'case' [Expression] ':' [Statement]*
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -7061,8 +7072,8 @@
 /**
  * The default case in a switch statement.
  *
- * > switchDefault ::=
- * >     [SimpleIdentifier]* 'default' ':' [Statement]*
+ *    switchDefault ::=
+ *        [SimpleIdentifier]* 'default' ':' [Statement]*
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -7078,9 +7089,9 @@
 /**
  * An element within a switch statement.
  *
- * > switchMember ::=
- * >     switchCase
- * >   | switchDefault
+ *    switchMember ::=
+ *        switchCase
+ *      | switchDefault
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -7123,8 +7134,8 @@
 /**
  * A switch statement.
  *
- * > switchStatement ::=
- * >     'switch' '(' [Expression] ')' '{' [SwitchCase]* [SwitchDefault]? '}'
+ *    switchStatement ::=
+ *        'switch' '(' [Expression] ')' '{' [SwitchCase]* [SwitchDefault]? '}'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -7213,8 +7224,8 @@
 /**
  * A symbol literal expression.
  *
- * > symbolLiteral ::=
- * >     '#' (operator | (identifier ('.' identifier)*))
+ *    symbolLiteral ::=
+ *        '#' (operator | (identifier ('.' identifier)*))
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -7244,8 +7255,8 @@
 /**
  * A this expression.
  *
- * > thisExpression ::=
- * >     'this'
+ *    thisExpression ::=
+ *        'this'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -7269,8 +7280,8 @@
 /**
  * A throw expression.
  *
- * > throwExpression ::=
- * >     'throw' [Expression]
+ *    throwExpression ::=
+ *        'throw' [Expression]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -7306,9 +7317,9 @@
 /**
  * The declaration of one or more top-level variables of the same type.
  *
- * > topLevelVariableDeclaration ::=
- * >     ('final' | 'const') type? staticFinalDeclarationList ';'
- * >   | variableDeclaration ';'
+ *    topLevelVariableDeclaration ::=
+ *        ('final' | 'const') type? staticFinalDeclarationList ';'
+ *      | variableDeclaration ';'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -7349,11 +7360,11 @@
 /**
  * A try statement.
  *
- * > tryStatement ::=
- * >     'try' [Block] ([CatchClause]+ finallyClause? | finallyClause)
- * >
- * > finallyClause ::=
- * >     'finally' [Block]
+ *    tryStatement ::=
+ *        'try' [Block] ([CatchClause]+ finallyClause? | finallyClause)
+ *
+ *    finallyClause ::=
+ *        'finally' [Block]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -7421,12 +7432,12 @@
 /**
  * The declaration of a type alias.
  *
- * > typeAlias ::=
- * >     'typedef' typeAliasBody
- * >
- * > typeAliasBody ::=
- * >     classTypeAlias
- * >   | functionTypeAlias
+ *    typeAlias ::=
+ *        'typedef' typeAliasBody
+ *
+ *    typeAliasBody ::=
+ *        classTypeAlias
+ *      | functionTypeAlias
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -7455,8 +7466,8 @@
 /**
  * A list of type arguments.
  *
- * > typeArguments ::=
- * >     '<' typeName (',' typeName)* '>'
+ *    typeArguments ::=
+ *        '<' typeName (',' typeName)* '>'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -7497,9 +7508,9 @@
 /**
  * A literal that has a type associated with it.
  *
- * > typedLiteral ::=
- * >     [ListLiteral]
- * >   | [MapLiteral]
+ *    typedLiteral ::=
+ *        [ListLiteral]
+ *      | [MapLiteral]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -7531,8 +7542,8 @@
 /**
  * The name of a type, which can optionally include type arguments.
  *
- * > typeName ::=
- * >     [Identifier] typeArguments?
+ *    typeName ::=
+ *        [Identifier] typeArguments?
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -7589,8 +7600,8 @@
 /**
  * A type parameter.
  *
- * > typeParameter ::=
- * >     [SimpleIdentifier] ('extends' [TypeName])?
+ *    typeParameter ::=
+ *        [SimpleIdentifier] ('extends' [TypeName])?
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -7645,8 +7656,8 @@
 /**
  * Type parameters within a declaration.
  *
- * > typeParameterList ::=
- * >     '<' [TypeParameter] (',' [TypeParameter])* '>'
+ *    typeParameterList ::=
+ *        '<' [TypeParameter] (',' [TypeParameter])* '>'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -7678,10 +7689,10 @@
 /**
  * A directive that references a URI.
  *
- * > uriBasedDirective ::=
- * >     [ExportDirective]
- * >   | [ImportDirective]
- * >   | [PartDirective]
+ *    uriBasedDirective ::=
+ *        [ExportDirective]
+ *      | [ImportDirective]
+ *      | [PartDirective]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -7751,8 +7762,8 @@
  * An identifier that has an initial value associated with it. Instances of this
  * class are always children of the class [VariableDeclarationList].
  *
- * > variableDeclaration ::=
- * >     [SimpleIdentifier] ('=' [Expression])?
+ *    variableDeclaration ::=
+ *        [SimpleIdentifier] ('=' [Expression])?
  *
  * TODO(paulberry): the grammar does not allow metadata to be associated with
  * a VariableDeclaration, and currently we don't record comments for it either.
@@ -7823,14 +7834,14 @@
 /**
  * The declaration of one or more variables of the same type.
  *
- * > variableDeclarationList ::=
- * >     finalConstVarOrType [VariableDeclaration] (',' [VariableDeclaration])*
- * >
- * > finalConstVarOrType ::=
- * >   | 'final' [TypeName]?
- * >   | 'const' [TypeName]?
- * >   | 'var'
- * >   | [TypeName]
+ *    variableDeclarationList ::=
+ *        finalConstVarOrType [VariableDeclaration] (',' [VariableDeclaration])*
+ *
+ *    finalConstVarOrType ::=
+ *      | 'final' [TypeName]?
+ *      | 'const' [TypeName]?
+ *      | 'var'
+ *      | [TypeName]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -7895,8 +7906,8 @@
  * A list of variables that are being declared in a context where a statement is
  * required.
  *
- * > variableDeclarationStatement ::=
- * >     [VariableDeclarationList] ';'
+ *    variableDeclarationStatement ::=
+ *        [VariableDeclarationList] ';'
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -7932,8 +7943,8 @@
 /**
  * A while statement.
  *
- * > whileStatement ::=
- * >     'while' '(' [Expression] ')' [Statement]
+ *    whileStatement ::=
+ *        'while' '(' [Expression] ')' [Statement]
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -8004,8 +8015,8 @@
 /**
  * The with clause in a class declaration.
  *
- * > withClause ::=
- * >     'with' [TypeName] (',' [TypeName])*
+ *    withClause ::=
+ *        'with' [TypeName] (',' [TypeName])*
  *
  * Clients may not extend, implement or mix-in this class.
  */
@@ -8035,8 +8046,8 @@
 /**
  * A yield statement.
  *
- * > yieldStatement ::=
- * >     'yield' '*'? [Expression] ‘;’
+ *    yieldStatement ::=
+ *        'yield' '*'? [Expression] ‘;’
  *
  * Clients may not extend, implement or mix-in this class.
  */
diff --git a/pkg/analyzer/lib/dart/ast/visitor.dart b/pkg/analyzer/lib/dart/ast/visitor.dart
index 0cdb170..f76fb1d 100644
--- a/pkg/analyzer/lib/dart/ast/visitor.dart
+++ b/pkg/analyzer/lib/dart/ast/visitor.dart
@@ -93,6 +93,809 @@
 
 /**
  * An AST visitor that will recursively visit all of the nodes in an AST
+ * structure. For each node that is visited, the corresponding visit method on
+ * one or more other visitors (the 'delegates') will be invoked.
+ *
+ * For example, if an instance of this class is created with two delegates V1
+ * and V2, and that instance is used to visit the expression 'x + 1', then the
+ * following visit methods will be invoked:
+ * 1. V1.visitBinaryExpression
+ * 2. V2.visitBinaryExpression
+ * 3. V1.visitSimpleIdentifier
+ * 4. V2.visitSimpleIdentifier
+ * 5. V1.visitIntegerLiteral
+ * 6. V2.visitIntegerLiteral
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class DelegatingAstVisitor<T> implements AstVisitor<T> {
+  /**
+   * The delegates whose visit methods will be invoked.
+   */
+  final Iterable<AstVisitor<T>> _delegates;
+
+  /**
+   * Initialize a newly created visitor to use each of the given delegate
+   * visitors to visit the nodes of an AST structure.
+   */
+  DelegatingAstVisitor(this._delegates);
+
+  @override
+  T visitAdjacentStrings(AdjacentStrings node) {
+    _delegates.forEach((delegate) => delegate.visitAdjacentStrings(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitAnnotation(Annotation node) {
+    _delegates.forEach((delegate) => delegate.visitAnnotation(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitArgumentList(ArgumentList node) {
+    _delegates.forEach((delegate) => delegate.visitArgumentList(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitAsExpression(AsExpression node) {
+    _delegates.forEach((delegate) => delegate.visitAsExpression(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitAssertStatement(AssertStatement node) {
+    _delegates.forEach((delegate) => delegate.visitAssertStatement(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitAssignmentExpression(AssignmentExpression node) {
+    _delegates.forEach((delegate) => delegate.visitAssignmentExpression(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitAwaitExpression(AwaitExpression node) {
+    _delegates.forEach((delegate) => delegate.visitAwaitExpression(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitBinaryExpression(BinaryExpression node) {
+    _delegates.forEach((delegate) => delegate.visitBinaryExpression(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitBlock(Block node) {
+    _delegates.forEach((delegate) => delegate.visitBlock(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitBlockFunctionBody(BlockFunctionBody node) {
+    _delegates.forEach((delegate) => delegate.visitBlockFunctionBody(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitBooleanLiteral(BooleanLiteral node) {
+    _delegates.forEach((delegate) => delegate.visitBooleanLiteral(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitBreakStatement(BreakStatement node) {
+    _delegates.forEach((delegate) => delegate.visitBreakStatement(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitCascadeExpression(CascadeExpression node) {
+    _delegates.forEach((delegate) => delegate.visitCascadeExpression(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitCatchClause(CatchClause node) {
+    _delegates.forEach((delegate) => delegate.visitCatchClause(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitClassDeclaration(ClassDeclaration node) {
+    _delegates.forEach((delegate) => delegate.visitClassDeclaration(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitClassTypeAlias(ClassTypeAlias node) {
+    _delegates.forEach((delegate) => delegate.visitClassTypeAlias(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitComment(Comment node) {
+    _delegates.forEach((delegate) => delegate.visitComment(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitCommentReference(CommentReference node) {
+    _delegates.forEach((delegate) => delegate.visitCommentReference(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitCompilationUnit(CompilationUnit node) {
+    _delegates.forEach((delegate) => delegate.visitCompilationUnit(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitConditionalExpression(ConditionalExpression node) {
+    _delegates.forEach((delegate) => delegate.visitConditionalExpression(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitConfiguration(Configuration node) {
+    _delegates.forEach((delegate) => delegate.visitConfiguration(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitConstructorDeclaration(ConstructorDeclaration node) {
+    _delegates
+        .forEach((delegate) => delegate.visitConstructorDeclaration(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
+    _delegates
+        .forEach((delegate) => delegate.visitConstructorFieldInitializer(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitConstructorName(ConstructorName node) {
+    _delegates.forEach((delegate) => delegate.visitConstructorName(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitContinueStatement(ContinueStatement node) {
+    _delegates.forEach((delegate) => delegate.visitContinueStatement(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitDeclaredIdentifier(DeclaredIdentifier node) {
+    _delegates.forEach((delegate) => delegate.visitDeclaredIdentifier(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitDefaultFormalParameter(DefaultFormalParameter node) {
+    _delegates
+        .forEach((delegate) => delegate.visitDefaultFormalParameter(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitDoStatement(DoStatement node) {
+    _delegates.forEach((delegate) => delegate.visitDoStatement(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitDottedName(DottedName node) {
+    _delegates.forEach((delegate) => delegate.visitDottedName(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitDoubleLiteral(DoubleLiteral node) {
+    _delegates.forEach((delegate) => delegate.visitDoubleLiteral(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitEmptyFunctionBody(EmptyFunctionBody node) {
+    _delegates.forEach((delegate) => delegate.visitEmptyFunctionBody(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitEmptyStatement(EmptyStatement node) {
+    _delegates.forEach((delegate) => delegate.visitEmptyStatement(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitEnumConstantDeclaration(EnumConstantDeclaration node) {
+    _delegates
+        .forEach((delegate) => delegate.visitEnumConstantDeclaration(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitEnumDeclaration(EnumDeclaration node) {
+    _delegates.forEach((delegate) => delegate.visitEnumDeclaration(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitExportDirective(ExportDirective node) {
+    _delegates.forEach((delegate) => delegate.visitExportDirective(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitExpressionFunctionBody(ExpressionFunctionBody node) {
+    _delegates
+        .forEach((delegate) => delegate.visitExpressionFunctionBody(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitExpressionStatement(ExpressionStatement node) {
+    _delegates.forEach((delegate) => delegate.visitExpressionStatement(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitExtendsClause(ExtendsClause node) {
+    _delegates.forEach((delegate) => delegate.visitExtendsClause(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitFieldDeclaration(FieldDeclaration node) {
+    _delegates.forEach((delegate) => delegate.visitFieldDeclaration(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitFieldFormalParameter(FieldFormalParameter node) {
+    _delegates.forEach((delegate) => delegate.visitFieldFormalParameter(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitForEachStatement(ForEachStatement node) {
+    _delegates.forEach((delegate) => delegate.visitForEachStatement(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitFormalParameterList(FormalParameterList node) {
+    _delegates.forEach((delegate) => delegate.visitFormalParameterList(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitForStatement(ForStatement node) {
+    _delegates.forEach((delegate) => delegate.visitForStatement(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitFunctionDeclaration(FunctionDeclaration node) {
+    _delegates.forEach((delegate) => delegate.visitFunctionDeclaration(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitFunctionDeclarationStatement(FunctionDeclarationStatement node) {
+    _delegates.forEach(
+        (delegate) => delegate.visitFunctionDeclarationStatement(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitFunctionExpression(FunctionExpression node) {
+    _delegates.forEach((delegate) => delegate.visitFunctionExpression(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
+    _delegates.forEach(
+        (delegate) => delegate.visitFunctionExpressionInvocation(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitFunctionTypeAlias(FunctionTypeAlias node) {
+    _delegates.forEach((delegate) => delegate.visitFunctionTypeAlias(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
+    _delegates.forEach(
+        (delegate) => delegate.visitFunctionTypedFormalParameter(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitHideCombinator(HideCombinator node) {
+    _delegates.forEach((delegate) => delegate.visitHideCombinator(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitIfStatement(IfStatement node) {
+    _delegates.forEach((delegate) => delegate.visitIfStatement(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitImplementsClause(ImplementsClause node) {
+    _delegates.forEach((delegate) => delegate.visitImplementsClause(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitImportDirective(ImportDirective node) {
+    _delegates.forEach((delegate) => delegate.visitImportDirective(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitIndexExpression(IndexExpression node) {
+    _delegates.forEach((delegate) => delegate.visitIndexExpression(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitInstanceCreationExpression(InstanceCreationExpression node) {
+    _delegates
+        .forEach((delegate) => delegate.visitInstanceCreationExpression(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitIntegerLiteral(IntegerLiteral node) {
+    _delegates.forEach((delegate) => delegate.visitIntegerLiteral(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitInterpolationExpression(InterpolationExpression node) {
+    _delegates
+        .forEach((delegate) => delegate.visitInterpolationExpression(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitInterpolationString(InterpolationString node) {
+    _delegates.forEach((delegate) => delegate.visitInterpolationString(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitIsExpression(IsExpression node) {
+    _delegates.forEach((delegate) => delegate.visitIsExpression(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitLabel(Label node) {
+    _delegates.forEach((delegate) => delegate.visitLabel(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitLabeledStatement(LabeledStatement node) {
+    _delegates.forEach((delegate) => delegate.visitLabeledStatement(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitLibraryDirective(LibraryDirective node) {
+    _delegates.forEach((delegate) => delegate.visitLibraryDirective(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitLibraryIdentifier(LibraryIdentifier node) {
+    _delegates.forEach((delegate) => delegate.visitLibraryIdentifier(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitListLiteral(ListLiteral node) {
+    _delegates.forEach((delegate) => delegate.visitListLiteral(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitMapLiteral(MapLiteral node) {
+    _delegates.forEach((delegate) => delegate.visitMapLiteral(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitMapLiteralEntry(MapLiteralEntry node) {
+    _delegates.forEach((delegate) => delegate.visitMapLiteralEntry(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitMethodDeclaration(MethodDeclaration node) {
+    _delegates.forEach((delegate) => delegate.visitMethodDeclaration(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitMethodInvocation(MethodInvocation node) {
+    _delegates.forEach((delegate) => delegate.visitMethodInvocation(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitNamedExpression(NamedExpression node) {
+    _delegates.forEach((delegate) => delegate.visitNamedExpression(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitNativeClause(NativeClause node) {
+    _delegates.forEach((delegate) => delegate.visitNativeClause(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitNativeFunctionBody(NativeFunctionBody node) {
+    _delegates.forEach((delegate) => delegate.visitNativeFunctionBody(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitNullLiteral(NullLiteral node) {
+    _delegates.forEach((delegate) => delegate.visitNullLiteral(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitParenthesizedExpression(ParenthesizedExpression node) {
+    _delegates
+        .forEach((delegate) => delegate.visitParenthesizedExpression(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitPartDirective(PartDirective node) {
+    _delegates.forEach((delegate) => delegate.visitPartDirective(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitPartOfDirective(PartOfDirective node) {
+    _delegates.forEach((delegate) => delegate.visitPartOfDirective(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitPostfixExpression(PostfixExpression node) {
+    _delegates.forEach((delegate) => delegate.visitPostfixExpression(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitPrefixedIdentifier(PrefixedIdentifier node) {
+    _delegates.forEach((delegate) => delegate.visitPrefixedIdentifier(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitPrefixExpression(PrefixExpression node) {
+    _delegates.forEach((delegate) => delegate.visitPrefixExpression(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitPropertyAccess(PropertyAccess node) {
+    _delegates.forEach((delegate) => delegate.visitPropertyAccess(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitRedirectingConstructorInvocation(
+      RedirectingConstructorInvocation node) {
+    _delegates.forEach(
+        (delegate) => delegate.visitRedirectingConstructorInvocation(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitRethrowExpression(RethrowExpression node) {
+    _delegates.forEach((delegate) => delegate.visitRethrowExpression(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitReturnStatement(ReturnStatement node) {
+    _delegates.forEach((delegate) => delegate.visitReturnStatement(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitScriptTag(ScriptTag node) {
+    _delegates.forEach((delegate) => delegate.visitScriptTag(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitShowCombinator(ShowCombinator node) {
+    _delegates.forEach((delegate) => delegate.visitShowCombinator(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitSimpleFormalParameter(SimpleFormalParameter node) {
+    _delegates.forEach((delegate) => delegate.visitSimpleFormalParameter(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitSimpleIdentifier(SimpleIdentifier node) {
+    _delegates.forEach((delegate) => delegate.visitSimpleIdentifier(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitSimpleStringLiteral(SimpleStringLiteral node) {
+    _delegates.forEach((delegate) => delegate.visitSimpleStringLiteral(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitStringInterpolation(StringInterpolation node) {
+    _delegates.forEach((delegate) => delegate.visitStringInterpolation(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitSuperConstructorInvocation(SuperConstructorInvocation node) {
+    _delegates
+        .forEach((delegate) => delegate.visitSuperConstructorInvocation(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitSuperExpression(SuperExpression node) {
+    _delegates.forEach((delegate) => delegate.visitSuperExpression(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitSwitchCase(SwitchCase node) {
+    _delegates.forEach((delegate) => delegate.visitSwitchCase(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitSwitchDefault(SwitchDefault node) {
+    _delegates.forEach((delegate) => delegate.visitSwitchDefault(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitSwitchStatement(SwitchStatement node) {
+    _delegates.forEach((delegate) => delegate.visitSwitchStatement(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitSymbolLiteral(SymbolLiteral node) {
+    _delegates.forEach((delegate) => delegate.visitSymbolLiteral(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitThisExpression(ThisExpression node) {
+    _delegates.forEach((delegate) => delegate.visitThisExpression(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitThrowExpression(ThrowExpression node) {
+    _delegates.forEach((delegate) => delegate.visitThrowExpression(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
+    _delegates
+        .forEach((delegate) => delegate.visitTopLevelVariableDeclaration(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitTryStatement(TryStatement node) {
+    _delegates.forEach((delegate) => delegate.visitTryStatement(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitTypeArgumentList(TypeArgumentList node) {
+    _delegates.forEach((delegate) => delegate.visitTypeArgumentList(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitTypeName(TypeName node) {
+    _delegates.forEach((delegate) => delegate.visitTypeName(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitTypeParameter(TypeParameter node) {
+    _delegates.forEach((delegate) => delegate.visitTypeParameter(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitTypeParameterList(TypeParameterList node) {
+    _delegates.forEach((delegate) => delegate.visitTypeParameterList(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitVariableDeclaration(VariableDeclaration node) {
+    _delegates.forEach((delegate) => delegate.visitVariableDeclaration(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitVariableDeclarationList(VariableDeclarationList node) {
+    _delegates
+        .forEach((delegate) => delegate.visitVariableDeclarationList(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitVariableDeclarationStatement(VariableDeclarationStatement node) {
+    _delegates.forEach(
+        (delegate) => delegate.visitVariableDeclarationStatement(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitWhileStatement(WhileStatement node) {
+    _delegates.forEach((delegate) => delegate.visitWhileStatement(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitWithClause(WithClause node) {
+    _delegates.forEach((delegate) => delegate.visitWithClause(node));
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  T visitYieldStatement(YieldStatement node) {
+    _delegates.forEach((delegate) => delegate.visitYieldStatement(node));
+    node.visitChildren(this);
+    return null;
+  }
+}
+
+/**
+ * An AST visitor that will recursively visit all of the nodes in an AST
  * structure (like instances of the class [RecursiveAstVisitor]). In addition,
  * when a node of a specific type is visited not only will the visit method for
  * that specific type of node be invoked, but additional methods for the
diff --git a/pkg/analyzer/lib/dart/element/element.dart b/pkg/analyzer/lib/dart/element/element.dart
index d210229..e89eb22 100644
--- a/pkg/analyzer/lib/dart/element/element.dart
+++ b/pkg/analyzer/lib/dart/element/element.dart
@@ -635,6 +635,11 @@
   bool get isPrivate;
 
   /**
+   * Return `true` if this element has an annotation of the form '@protected'.
+   */
+  bool get isProtected;
+
+  /**
    * Return `true` if this element is public. Public elements are visible within
    * any library that imports the library in which they are declared.
    */
@@ -808,6 +813,13 @@
    */
   bool get isOverride;
 
+
+  /**
+   * Return `true` if this annotation marks the associated member as being
+   * protected.
+   */
+  bool get isProtected;
+
   /**
    * Return `true` if this annotation marks the associated class as implementing
    * a proxy object.
@@ -1313,6 +1325,12 @@
   static const List<LibraryElement> EMPTY_LIST = const <LibraryElement>[];
 
   /**
+   * Return a list containing the strongly connected component in the
+   * import/export graph in which the current library resides.
+   */
+  List<LibraryElement> get libraryCycle;
+
+  /**
    * Return the compilation unit that defines this library.
    */
   CompilationUnitElement get definingCompilationUnit;
diff --git a/pkg/analyzer/lib/file_system/file_system.dart b/pkg/analyzer/lib/file_system/file_system.dart
index 05bd4e7..c9b3e96 100644
--- a/pkg/analyzer/lib/file_system/file_system.dart
+++ b/pkg/analyzer/lib/file_system/file_system.dart
@@ -47,6 +47,7 @@
 
   FileSystemException(this.path, this.message);
 
+  @override
   String toString() => 'FileSystemException(path=$path; message=$message)';
 }
 
diff --git a/pkg/analyzer/lib/file_system/memory_file_system.dart b/pkg/analyzer/lib/file_system/memory_file_system.dart
index a8aca38..fd26eb1 100644
--- a/pkg/analyzer/lib/file_system/memory_file_system.dart
+++ b/pkg/analyzer/lib/file_system/memory_file_system.dart
@@ -29,6 +29,7 @@
   int nextStamp = 0;
 
   final Context _pathContext;
+  @override
   final AbsolutePathContext absolutePathContext;
 
   MemoryResourceProvider({bool isWindows: false})
@@ -211,6 +212,7 @@
   @override
   bool get exists => false;
 
+  @override
   int get modificationStamp {
     int stamp = _provider._pathToTimestamp[path];
     if (stamp == null) {
@@ -249,6 +251,7 @@
   @override
   bool get exists => _provider._pathToResource[path] is _MemoryFile;
 
+  @override
   int get modificationStamp {
     int stamp = _provider._pathToTimestamp[path];
     if (stamp == null) {
@@ -303,6 +306,7 @@
 
   final _MemoryFile file;
 
+  @override
   final Uri uri;
 
   /**
@@ -453,6 +457,7 @@
  */
 abstract class _MemoryResource implements Resource {
   final MemoryResourceProvider _provider;
+  @override
   final String path;
 
   _MemoryResource(this._provider, this.path);
diff --git a/pkg/analyzer/lib/file_system/physical_file_system.dart b/pkg/analyzer/lib/file_system/physical_file_system.dart
index e7a83a4..cdfa9a6 100644
--- a/pkg/analyzer/lib/file_system/physical_file_system.dart
+++ b/pkg/analyzer/lib/file_system/physical_file_system.dart
@@ -31,6 +31,7 @@
    */
   static final String SERVER_DIR = ".dartServer";
 
+  @override
   final AbsolutePathContext absolutePathContext =
       new AbsolutePathContext(io.Platform.isWindows);
 
diff --git a/pkg/analyzer/lib/source/path_filter.dart b/pkg/analyzer/lib/source/path_filter.dart
index f449610..816bc55 100644
--- a/pkg/analyzer/lib/source/path_filter.dart
+++ b/pkg/analyzer/lib/source/path_filter.dart
@@ -44,6 +44,7 @@
     }
   }
 
+  @override
   String toString() {
     StringBuffer sb = new StringBuffer();
     for (Glob pattern in _ignorePatterns) {
diff --git a/pkg/analyzer/lib/src/context/context.dart b/pkg/analyzer/lib/src/context/context.dart
index cc1d41e..def719f 100644
--- a/pkg/analyzer/lib/src/context/context.dart
+++ b/pkg/analyzer/lib/src/context/context.dart
@@ -72,6 +72,7 @@
    * A client-provided name used to identify this context, or `null` if the
    * client has not provided a name.
    */
+  @override
   String name;
 
   /**
@@ -129,6 +130,7 @@
   /**
    * A list of all [WorkManager]s used by this context.
    */
+  @override
   final List<WorkManager> workManagers = <WorkManager>[];
 
   /**
@@ -260,6 +262,8 @@
             options.enableStrictCallChecks ||
         this._options.enableGenericMethods != options.enableGenericMethods ||
         this._options.enableAsync != options.enableAsync ||
+        this._options.enableConditionalDirectives !=
+            options.enableConditionalDirectives ||
         this._options.enableSuperMixins != options.enableSuperMixins;
     int cacheSize = options.cacheSize;
     if (this._options.cacheSize != cacheSize) {
@@ -274,6 +278,8 @@
     this._options.enableAssertMessage = options.enableAssertMessage;
     this._options.enableStrictCallChecks = options.enableStrictCallChecks;
     this._options.enableAsync = options.enableAsync;
+    this._options.enableConditionalDirectives =
+        options.enableConditionalDirectives;
     this._options.enableSuperMixins = options.enableSuperMixins;
     this._options.hint = options.hint;
     this._options.incremental = options.incremental;
@@ -486,6 +492,7 @@
   /**
    * Sets the [TypeProvider] for this context.
    */
+  @override
   void set typeProvider(TypeProvider typeProvider) {
     _typeProvider = typeProvider;
   }
@@ -1017,7 +1024,9 @@
       if (changed) {
         if (!analysisOptions.incremental ||
             !_tryPoorMansIncrementalResolution(source, newContents)) {
-          _sourceChanged(source);
+          // Don't compare with old contents because the cache has already been
+          // updated, and we know at this point that it changed.
+          _sourceChanged(source, compareWithOld: false);
         }
         entry.modificationTime = _contentCache.getModificationStamp(source);
         entry.setValue(CONTENT, newContents, TargetedResult.EMPTY_LIST);
@@ -1754,21 +1763,28 @@
   /**
    * Invalidate the [source] that was changed and any sources that referenced
    * the source before it existed.
+   *
+   * Note: source may be considered "changed" if it was previously missing,
+   * but pointed to by an import or export directive.
    */
-  void _sourceChanged(Source source) {
+  void _sourceChanged(Source source, {bool compareWithOld: true}) {
     CacheEntry entry = _cache.get(source);
-    // If the source is removed, we don't care about it.
+    // If the source has no cache entry, there is nothing to invalidate.
     if (entry == null) {
       return;
     }
-    // Check whether the content of the source is the same as it was the last
-    // time.
-    String sourceContent = entry.getValue(CONTENT);
-    if (sourceContent != null) {
-      entry.setState(CONTENT, CacheState.FLUSHED);
+
+    String oldContents = compareWithOld ? entry.getValue(CONTENT) : null;
+
+    // Flush so that from now on we will get new contents.
+    // (For example, in getLibrariesContaining.)
+    entry.setState(CONTENT, CacheState.FLUSHED);
+
+    if (oldContents != null) {
+      // Fast path if the content is the same as it was last time.
       try {
         TimestampedData<String> fileContents = getContents(source);
-        if (fileContents.data == sourceContent) {
+        if (fileContents.data == oldContents) {
           int time = fileContents.modificationTime;
           for (CacheEntry entry in _entriesFor(source)) {
             entry.modificationTime = time;
@@ -1813,6 +1829,8 @@
         }
       }
       entry.setState(CONTENT, CacheState.INVALID);
+      entry.setState(MODIFICATION_TIME, CacheState.INVALID);
+      entry.setState(SOURCE_KIND, CacheState.INVALID);
     }
     driver.reset();
     for (WorkManager workManager in workManagers) {
diff --git a/pkg/analyzer/lib/src/context/source.dart b/pkg/analyzer/lib/src/context/source.dart
index faf8eaa..5d18886 100644
--- a/pkg/analyzer/lib/src/context/source.dart
+++ b/pkg/analyzer/lib/src/context/source.dart
@@ -23,6 +23,7 @@
   /**
    * The analysis context that this source factory is associated with.
    */
+  @override
   AnalysisContext context;
 
   /**
@@ -63,6 +64,7 @@
    * @return the [DartSdk] associated with this [SourceFactory], or `null` if
    *         there is no such SDK
    */
+  @override
   DartSdk get dartSdk {
     for (UriResolver resolver in resolvers) {
       if (resolver is DartUriResolver) {
@@ -78,12 +80,14 @@
    *
    * @param localSourcePredicate the predicate to determine is [Source] is local
    */
+  @override
   void set localSourcePredicate(LocalSourcePredicate localSourcePredicate) {
     this._localSourcePredicate = localSourcePredicate;
   }
 
   /// A table mapping package names to paths of directories containing
   /// the package (or [null] if there is no registered package URI resolver).
+  @override
   Map<String, List<Folder>> get packageMap {
     // Start by looking in .packages.
     if (_packages != null) {
@@ -108,6 +112,7 @@
    * Return a source factory that will resolve URI's in the same way that this
    * source factory does.
    */
+  @override
   SourceFactory clone() {
     SourceFactory factory =
         new SourceFactory(resolvers, _packages, _resourceProvider);
@@ -122,6 +127,7 @@
    * @param absoluteUri the absolute URI to be resolved
    * @return a source object representing the absolute URI
    */
+  @override
   Source forUri(String absoluteUri) {
     try {
       Uri uri = parseUriWithException(absoluteUri);
@@ -143,6 +149,7 @@
    * @param absoluteUri the absolute URI to be resolved
    * @return a source object representing the absolute URI
    */
+  @override
   Source forUri2(Uri absoluteUri) {
     if (absoluteUri.isAbsolute) {
       try {
@@ -165,6 +172,7 @@
    * @throws IllegalArgumentException if the argument is not a valid encoding
    * See [Source.encoding].
    */
+  @override
   Source fromEncoding(String encoding) {
     Source source = forUri(encoding);
     if (source == null) {
@@ -180,6 +188,7 @@
    * @param source the [Source] to analyze
    * @return `true` if the given [Source] is local
    */
+  @override
   bool isLocalSource(Source source) => _localSourcePredicate.isLocal(source);
 
   /**
@@ -189,6 +198,7 @@
    * if either the [containedUri] is invalid or if it cannot be resolved against
    * the [containingSource]'s URI.
    */
+  @override
   Source resolveUri(Source containingSource, String containedUri) {
     if (containedUri == null || containedUri.isEmpty) {
       return null;
@@ -217,6 +227,7 @@
    * @param source the source to get URI for
    * @return the absolute URI representing the given source
    */
+  @override
   Uri restoreUri(Source source) {
     // First see if a resolver can restore the URI.
     for (UriResolver resolver in resolvers) {
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index 48332fb..d2e09de 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -29,8 +29,8 @@
  * the same kind (single line or multi-line), this class doesn't enforce that
  * restriction.
  *
- * > adjacentStrings ::=
- * >     [StringLiteral] [StringLiteral]+
+ *    adjacentStrings ::=
+ *        [StringLiteral] [StringLiteral]+
  */
 class AdjacentStringsImpl extends StringLiteralImpl implements AdjacentStrings {
   /**
@@ -181,16 +181,17 @@
 /**
  * An annotation that can be associated with an AST node.
  *
- * > metadata ::=
- * >     annotation*
- * >
- * > annotation ::=
- * >     '@' [Identifier] ('.' [SimpleIdentifier])? [ArgumentList]?
+ *    metadata ::=
+ *        annotation*
+ *
+ *    annotation ::=
+ *        '@' [Identifier] ('.' [SimpleIdentifier])? [ArgumentList]?
  */
 class AnnotationImpl extends AstNodeImpl implements Annotation {
   /**
    * The at sign that introduced the annotation.
    */
+  @override
   Token atSign;
 
   /**
@@ -203,6 +204,7 @@
    * The period before the constructor name, or `null` if this annotation is not
    * the invocation of a named constructor.
    */
+  @override
   Token period;
 
   /**
@@ -226,6 +228,7 @@
   /**
    * The element annotation representing this annotation in the element model.
    */
+  @override
   ElementAnnotation elementAnnotation;
 
   /**
@@ -316,17 +319,18 @@
  * A list of arguments in the invocation of an executable element (that is, a
  * function, method, or constructor).
  *
- * > argumentList ::=
- * >     '(' arguments? ')'
- * >
- * > arguments ::=
- * >     [NamedExpression] (',' [NamedExpression])*
- * >   | [Expression] (',' [Expression])* (',' [NamedExpression])*
+ *    argumentList ::=
+ *        '(' arguments? ')'
+ *
+ *    arguments ::=
+ *        [NamedExpression] (',' [NamedExpression])*
+ *      | [Expression] (',' [Expression])* (',' [NamedExpression])*
  */
 class ArgumentListImpl extends AstNodeImpl implements ArgumentList {
   /**
    * The left parenthesis.
    */
+  @override
   Token leftParenthesis;
 
   /**
@@ -337,6 +341,7 @@
   /**
    * The right parenthesis.
    */
+  @override
   Token rightParenthesis;
 
   /**
@@ -468,8 +473,8 @@
 /**
  * An as expression.
  *
- * > asExpression ::=
- * >     [Expression] 'as' [TypeName]
+ *    asExpression ::=
+ *        [Expression] 'as' [TypeName]
  */
 class AsExpressionImpl extends ExpressionImpl implements AsExpression {
   /**
@@ -480,6 +485,7 @@
   /**
    * The 'as' operator.
    */
+  @override
   Token asOperator;
 
   /**
@@ -537,18 +543,20 @@
 /**
  * An assert statement.
  *
- * > assertStatement ::=
- * >     'assert' '(' [Expression] ')' ';'
+ *    assertStatement ::=
+ *        'assert' '(' [Expression] ')' ';'
  */
 class AssertStatementImpl extends StatementImpl implements AssertStatement {
   /**
    * The token representing the 'assert' keyword.
    */
+  @override
   Token assertKeyword;
 
   /**
    * The left parenthesis.
    */
+  @override
   Token leftParenthesis;
 
   /**
@@ -559,6 +567,7 @@
   /**
    * The comma, if a message expression was supplied.  Otherwise `null`.
    */
+  @override
   Token comma;
 
   /**
@@ -570,11 +579,13 @@
   /**
    * The right parenthesis.
    */
+  @override
   Token rightParenthesis;
 
   /**
    * The semicolon terminating the statement.
    */
+  @override
   Token semicolon;
 
   /**
@@ -637,8 +648,8 @@
 /**
  * An assignment expression.
  *
- * > assignmentExpression ::=
- * >     [Expression] operator [Expression]
+ *    assignmentExpression ::=
+ *        [Expression] operator [Expression]
  */
 class AssignmentExpressionImpl extends ExpressionImpl
     implements AssignmentExpression {
@@ -650,6 +661,7 @@
   /**
    * The assignment operator being applied.
    */
+  @override
   Token operator;
 
   /**
@@ -663,6 +675,7 @@
    * the operator is not a compound operator, or if the operator could not be
    * resolved.
    */
+  @override
   MethodElement staticElement;
 
   /**
@@ -671,6 +684,7 @@
    * if the operator is not a compound operator, or if the operator could not be
    * resolved.
    */
+  @override
   MethodElement propagatedElement;
 
   /**
@@ -941,13 +955,14 @@
 /**
  * An await expression.
  *
- * > awaitExpression ::=
- * >     'await' [Expression]
+ *    awaitExpression ::=
+ *        'await' [Expression]
  */
 class AwaitExpressionImpl extends ExpressionImpl implements AwaitExpression {
   /**
    * The 'await' keyword.
    */
+  @override
   Token awaitKeyword;
 
   /**
@@ -1000,8 +1015,8 @@
 /**
  * A binary (infix) expression.
  *
- * > binaryExpression ::=
- * >     [Expression] [Token] [Expression]
+ *    binaryExpression ::=
+ *        [Expression] [Token] [Expression]
  */
 class BinaryExpressionImpl extends ExpressionImpl implements BinaryExpression {
   /**
@@ -1012,6 +1027,7 @@
   /**
    * The binary operator being applied.
    */
+  @override
   Token operator;
 
   /**
@@ -1024,6 +1040,7 @@
    * left operand, or `null` if the AST structure has not been resolved, if the
    * operator is not user definable, or if the operator could not be resolved.
    */
+  @override
   MethodElement staticElement;
 
   /**
@@ -1032,6 +1049,7 @@
    * the operator is not user definable, or if the operator could not be
    * resolved.
    */
+  @override
   MethodElement propagatedElement;
 
   /**
@@ -1128,8 +1146,8 @@
 /**
  * A function body that consists of a block of statements.
  *
- * > blockFunctionBody ::=
- * >     ('async' | 'async' '*' | 'sync' '*')? [Block]
+ *    blockFunctionBody ::=
+ *        ('async' | 'async' '*' | 'sync' '*')? [Block]
  */
 class BlockFunctionBodyImpl extends FunctionBodyImpl
     implements BlockFunctionBody {
@@ -1137,12 +1155,14 @@
    * The token representing the 'async' or 'sync' keyword, or `null` if there is
    * no such keyword.
    */
+  @override
   Token keyword;
 
   /**
    * The star optionally following the 'async' or 'sync' keyword, or `null` if
    * there is wither no such keyword or no star.
    */
+  @override
   Token star;
 
   /**
@@ -1204,13 +1224,14 @@
 /**
  * A sequence of statements.
  *
- * > block ::=
- * >     '{' statement* '}'
+ *    block ::=
+ *        '{' statement* '}'
  */
 class BlockImpl extends StatementImpl implements Block {
   /**
    * The left curly bracket.
    */
+  @override
   Token leftBracket;
 
   /**
@@ -1221,6 +1242,7 @@
   /**
    * The right curly bracket.
    */
+  @override
   Token rightBracket;
 
   /**
@@ -1257,18 +1279,20 @@
 /**
  * A boolean literal expression.
  *
- * > booleanLiteral ::=
- * >     'false' | 'true'
+ *    booleanLiteral ::=
+ *        'false' | 'true'
  */
 class BooleanLiteralImpl extends LiteralImpl implements BooleanLiteral {
   /**
    * The token representing the literal.
    */
+  @override
   Token literal;
 
   /**
    * The value of the literal.
    */
+  @override
   bool value = false;
 
   /**
@@ -1300,13 +1324,14 @@
 /**
  * A break statement.
  *
- * > breakStatement ::=
- * >     'break' [SimpleIdentifier]? ';'
+ *    breakStatement ::=
+ *        'break' [SimpleIdentifier]? ';'
  */
 class BreakStatementImpl extends StatementImpl implements BreakStatement {
   /**
    * The token representing the 'break' keyword.
    */
+  @override
   Token breakKeyword;
 
   /**
@@ -1317,6 +1342,7 @@
   /**
    * The semicolon terminating the statement.
    */
+  @override
   Token semicolon;
 
   /**
@@ -1328,6 +1354,7 @@
    * resolved. Note that if the source code has errors, the target might be
    * invalid (e.g. trying to break to a switch case).
    */
+  @override
   AstNode target;
 
   /**
@@ -1371,16 +1398,16 @@
  * There are three kinds of expressions that can be used in a cascade
  * expression: [IndexExpression], [MethodInvocation] and [PropertyAccess].
  *
- * > cascadeExpression ::=
- * >     [Expression] cascadeSection*
- * >
- * > cascadeSection ::=
- * >     '..'  (cascadeSelector arguments*) (assignableSelector arguments*)*
- * >     (assignmentOperator expressionWithoutCascade)?
- * >
- * > cascadeSelector ::=
- * >     '[ ' expression '] '
- * >   | identifier
+ *    cascadeExpression ::=
+ *        [Expression] cascadeSection*
+ *
+ *    cascadeSection ::=
+ *        '..'  (cascadeSelector arguments*) (assignableSelector arguments*)*
+ *        (assignmentOperator expressionWithoutCascade)?
+ *
+ *    cascadeSelector ::=
+ *        '[ ' expression '] '
+ *      | identifier
  */
 class CascadeExpressionImpl extends ExpressionImpl
     implements CascadeExpression {
@@ -1441,18 +1468,19 @@
 /**
  * A catch clause within a try statement.
  *
- * > onPart ::=
- * >     catchPart [Block]
- * >   | 'on' type catchPart? [Block]
- * >
- * > catchPart ::=
- * >     'catch' '(' [SimpleIdentifier] (',' [SimpleIdentifier])? ')'
+ *    onPart ::=
+ *        catchPart [Block]
+ *      | 'on' type catchPart? [Block]
+ *
+ *    catchPart ::=
+ *        'catch' '(' [SimpleIdentifier] (',' [SimpleIdentifier])? ')'
  */
 class CatchClauseImpl extends AstNodeImpl implements CatchClause {
   /**
    * The token representing the 'on' keyword, or `null` if there is no 'on'
    * keyword.
    */
+  @override
   Token onKeyword;
 
   /**
@@ -1465,11 +1493,13 @@
    * The token representing the 'catch' keyword, or `null` if there is no
    * 'catch' keyword.
    */
+  @override
   Token catchKeyword;
 
   /**
    * The left parenthesis, or `null` if there is no 'catch' keyword.
    */
+  @override
   Token leftParenthesis;
 
   /**
@@ -1482,6 +1512,7 @@
    * The comma separating the exception parameter from the stack trace
    * parameter, or `null` if there is no stack trace parameter.
    */
+  @override
   Token comma;
 
   /**
@@ -1493,6 +1524,7 @@
   /**
    * The right parenthesis, or `null` if there is no 'catch' keyword.
    */
+  @override
   Token rightParenthesis;
 
   /**
@@ -1624,22 +1656,24 @@
 /**
  * The declaration of a class.
  *
- * > classDeclaration ::=
- * >     'abstract'? 'class' [SimpleIdentifier] [TypeParameterList]?
- * >     ([ExtendsClause] [WithClause]?)?
- * >     [ImplementsClause]?
- * >     '{' [ClassMember]* '}'
+ *    classDeclaration ::=
+ *        'abstract'? 'class' [SimpleIdentifier] [TypeParameterList]?
+ *        ([ExtendsClause] [WithClause]?)?
+ *        [ImplementsClause]?
+ *        '{' [ClassMember]* '}'
  */
 class ClassDeclarationImpl extends NamedCompilationUnitMemberImpl
     implements ClassDeclaration {
   /**
    * The 'abstract' keyword, or `null` if the keyword was absent.
    */
+  @override
   Token abstractKeyword;
 
   /**
    * The token representing the 'class' keyword.
    */
+  @override
   Token classKeyword;
 
   /**
@@ -1675,6 +1709,7 @@
   /**
    * The left curly bracket.
    */
+  @override
   Token leftBracket;
 
   /**
@@ -1685,6 +1720,7 @@
   /**
    * The right curly bracket.
    */
+  @override
   Token rightBracket;
 
   /**
@@ -1874,11 +1910,11 @@
 /**
  * A class type alias.
  *
- * > classTypeAlias ::=
- * >     [SimpleIdentifier] [TypeParameterList]? '=' 'abstract'? mixinApplication
- * >
- * > mixinApplication ::=
- * >     [TypeName] [WithClause] [ImplementsClause]? ';'
+ *    classTypeAlias ::=
+ *        [SimpleIdentifier] [TypeParameterList]? '=' 'abstract'? mixinApplication
+ *
+ *    mixinApplication ::=
+ *        [TypeName] [WithClause] [ImplementsClause]? ';'
  */
 class ClassTypeAliasImpl extends TypeAliasImpl implements ClassTypeAlias {
   /**
@@ -1890,12 +1926,14 @@
   /**
    * The token for the '=' separating the name from the definition.
    */
+  @override
   Token equals;
 
   /**
    * The token for the 'abstract' keyword, or `null` if this is not defining an
    * abstract class.
    */
+  @override
   Token abstractKeyword;
 
   /**
@@ -2017,15 +2055,16 @@
 /**
  * A combinator associated with an import or export directive.
  *
- * > combinator ::=
- * >     [HideCombinator]
- * >   | [ShowCombinator]
+ *    combinator ::=
+ *        [HideCombinator]
+ *      | [ShowCombinator]
  */
 abstract class CombinatorImpl extends AstNodeImpl implements Combinator {
   /**
    * The 'hide' or 'show' keyword specifying what kind of processing is to be
    * done on the names.
    */
+  @override
   Token keyword;
 
   /**
@@ -2040,25 +2079,26 @@
 /**
  * A comment within the source code.
  *
- * > comment ::=
- * >     endOfLineComment
- * >   | blockComment
- * >   | documentationComment
- * >
- * > endOfLineComment ::=
- * >     '//' (CHARACTER - EOL)* EOL
- * >
- * > blockComment ::=
- * >     '/ *' CHARACTER* '&#42;/'
- * >
- * > documentationComment ::=
- * >     '/ **' (CHARACTER | [CommentReference])* '&#42;/'
- * >   | ('///' (CHARACTER - EOL)* EOL)+
+ *    comment ::=
+ *        endOfLineComment
+ *      | blockComment
+ *      | documentationComment
+ *
+ *    endOfLineComment ::=
+ *        '//' (CHARACTER - EOL)* EOL
+ *
+ *    blockComment ::=
+ *        '/ *' CHARACTER* '&#42;/'
+ *
+ *    documentationComment ::=
+ *        '/ **' (CHARACTER | [CommentReference])* '&#42;/'
+ *      | ('///' (CHARACTER - EOL)* EOL)+
  */
 class CommentImpl extends AstNodeImpl implements Comment {
   /**
    * The tokens representing the comment.
    */
+  @override
   final List<Token> tokens;
 
   /**
@@ -2143,14 +2183,15 @@
 /**
  * A reference to a Dart element that is found within a documentation comment.
  *
- * > commentReference ::=
- * >     '[' 'new'? [Identifier] ']'
+ *    commentReference ::=
+ *        '[' 'new'? [Identifier] ']'
  */
 class CommentReferenceImpl extends AstNodeImpl implements CommentReference {
   /**
    * The token representing the 'new' keyword, or `null` if there was no 'new'
    * keyword.
    */
+  @override
   Token newKeyword;
 
   /**
@@ -2235,25 +2276,26 @@
  * order even if lexical order does not conform to the restrictions of the
  * grammar.
  *
- * > compilationUnit ::=
- * >     directives declarations
- * >
- * > directives ::=
- * >     [ScriptTag]? [LibraryDirective]? namespaceDirective* [PartDirective]*
- * >   | [PartOfDirective]
- * >
- * > namespaceDirective ::=
- * >     [ImportDirective]
- * >   | [ExportDirective]
- * >
- * > declarations ::=
- * >     [CompilationUnitMember]*
+ *    compilationUnit ::=
+ *        directives declarations
+ *
+ *    directives ::=
+ *        [ScriptTag]? [LibraryDirective]? namespaceDirective* [PartDirective]*
+ *      | [PartOfDirective]
+ *
+ *    namespaceDirective ::=
+ *        [ImportDirective]
+ *      | [ExportDirective]
+ *
+ *    declarations ::=
+ *        [CompilationUnitMember]*
  */
 class CompilationUnitImpl extends AstNodeImpl implements CompilationUnit {
   /**
    * The first token in the token stream that was parsed to form this
    * compilation unit.
    */
+  @override
   Token beginToken;
 
   /**
@@ -2276,17 +2318,20 @@
    * The last token in the token stream that was parsed to form this compilation
    * unit. This token should always have a type of [TokenType.EOF].
    */
+  @override
   Token endToken;
 
   /**
    * The element associated with this compilation unit, or `null` if the AST
    * structure has not been resolved.
    */
+  @override
   CompilationUnitElement element;
 
   /**
    * The line information for this compilation unit.
    */
+  @override
   LineInfo lineInfo;
 
   /**
@@ -2386,13 +2431,13 @@
  * A node that declares one or more names within the scope of a compilation
  * unit.
  *
- * > compilationUnitMember ::=
- * >     [ClassDeclaration]
- * >   | [TypeAlias]
- * >   | [FunctionDeclaration]
- * >   | [MethodDeclaration]
- * >   | [VariableDeclaration]
- * >   | [VariableDeclaration]
+ *    compilationUnitMember ::=
+ *        [ClassDeclaration]
+ *      | [TypeAlias]
+ *      | [FunctionDeclaration]
+ *      | [MethodDeclaration]
+ *      | [VariableDeclaration]
+ *      | [VariableDeclaration]
  */
 abstract class CompilationUnitMemberImpl extends DeclarationImpl
     implements CompilationUnitMember {
@@ -2408,8 +2453,8 @@
 /**
  * A conditional expression.
  *
- * > conditionalExpression ::=
- * >     [Expression] '?' [Expression] ':' [Expression]
+ *    conditionalExpression ::=
+ *        [Expression] '?' [Expression] ':' [Expression]
  */
 class ConditionalExpressionImpl extends ExpressionImpl
     implements ConditionalExpression {
@@ -2421,6 +2466,7 @@
   /**
    * The token used to separate the condition from the then expression.
    */
+  @override
   Token question;
 
   /**
@@ -2431,6 +2477,7 @@
   /**
    * The token used to separate the then expression from the else expression.
    */
+  @override
   Token colon;
 
   /**
@@ -2513,11 +2560,15 @@
  *         identifier ('.' identifier)*
  */
 class ConfigurationImpl extends AstNodeImpl implements Configuration {
+  @override
   Token ifKeyword;
+  @override
   Token leftParenthesis;
   DottedName _name;
+  @override
   Token equalToken;
   StringLiteral _value;
+  @override
   Token rightParenthesis;
   StringLiteral _libraryUri;
 
@@ -2588,23 +2639,23 @@
 /**
  * A constructor declaration.
  *
- * > constructorDeclaration ::=
- * >     constructorSignature [FunctionBody]?
- * >   | constructorName formalParameterList ':' 'this' ('.' [SimpleIdentifier])? arguments
- * >
- * > constructorSignature ::=
- * >     'external'? constructorName formalParameterList initializerList?
- * >   | 'external'? 'factory' factoryName formalParameterList initializerList?
- * >   | 'external'? 'const'  constructorName formalParameterList initializerList?
- * >
- * > constructorName ::=
- * >     [SimpleIdentifier] ('.' [SimpleIdentifier])?
- * >
- * > factoryName ::=
- * >     [Identifier] ('.' [SimpleIdentifier])?
- * >
- * > initializerList ::=
- * >     ':' [ConstructorInitializer] (',' [ConstructorInitializer])*
+ *    constructorDeclaration ::=
+ *        constructorSignature [FunctionBody]?
+ *      | constructorName formalParameterList ':' 'this' ('.' [SimpleIdentifier])? arguments
+ *
+ *    constructorSignature ::=
+ *        'external'? constructorName formalParameterList initializerList?
+ *      | 'external'? 'factory' factoryName formalParameterList initializerList?
+ *      | 'external'? 'const'  constructorName formalParameterList initializerList?
+ *
+ *    constructorName ::=
+ *        [SimpleIdentifier] ('.' [SimpleIdentifier])?
+ *
+ *    factoryName ::=
+ *        [Identifier] ('.' [SimpleIdentifier])?
+ *
+ *    initializerList ::=
+ *        ':' [ConstructorInitializer] (',' [ConstructorInitializer])*
  */
 class ConstructorDeclarationImpl extends ClassMemberImpl
     implements ConstructorDeclaration {
@@ -2612,18 +2663,21 @@
    * The token for the 'external' keyword, or `null` if the constructor is not
    * external.
    */
+  @override
   Token externalKeyword;
 
   /**
    * The token for the 'const' keyword, or `null` if the constructor is not a
    * const constructor.
    */
+  @override
   Token constKeyword;
 
   /**
    * The token for the 'factory' keyword, or `null` if the constructor is not a
    * factory constructor.
    */
+  @override
   Token factoryKeyword;
 
   /**
@@ -2637,6 +2691,7 @@
    * The token for the period before the constructor name, or `null` if the
    * constructor being declared is unnamed.
    */
+  @override
   Token period;
 
   /**
@@ -2654,6 +2709,7 @@
    * The token for the separator (colon or equals) before the initializer list
    * or redirection, or `null` if there are no initializers.
    */
+  @override
   Token separator;
 
   /**
@@ -2678,6 +2734,7 @@
    * structure has not been resolved or if this constructor could not be
    * resolved.
    */
+  @override
   ConstructorElement element;
 
   /**
@@ -2813,20 +2870,22 @@
 /**
  * The initialization of a field within a constructor's initialization list.
  *
- * > fieldInitializer ::=
- * >     ('this' '.')? [SimpleIdentifier] '=' [Expression]
+ *    fieldInitializer ::=
+ *        ('this' '.')? [SimpleIdentifier] '=' [Expression]
  */
 class ConstructorFieldInitializerImpl extends ConstructorInitializerImpl
     implements ConstructorFieldInitializer {
   /**
    * The token for the 'this' keyword, or `null` if there is no 'this' keyword.
    */
+  @override
   Token thisKeyword;
 
   /**
    * The token for the period after the 'this' keyword, or `null` if there is no
    * 'this' keyword.
    */
+  @override
   Token period;
 
   /**
@@ -2837,6 +2896,7 @@
   /**
    * The token for the equal sign between the field name and the expression.
    */
+  @override
   Token equals;
 
   /**
@@ -2903,10 +2963,10 @@
 /**
  * A node that can occur in the initializer list of a constructor declaration.
  *
- * > constructorInitializer ::=
- * >     [SuperConstructorInvocation]
- * >   | [ConstructorFieldInitializer]
- * >   | [RedirectingConstructorInvocation]
+ *    constructorInitializer ::=
+ *        [SuperConstructorInvocation]
+ *      | [ConstructorFieldInitializer]
+ *      | [RedirectingConstructorInvocation]
  */
 abstract class ConstructorInitializerImpl extends AstNodeImpl
     implements ConstructorInitializer {}
@@ -2914,8 +2974,8 @@
 /**
  * The name of the constructor.
  *
- * > constructorName ::=
- * >     type ('.' identifier)?
+ *    constructorName ::=
+ *        type ('.' identifier)?
  */
 class ConstructorNameImpl extends AstNodeImpl implements ConstructorName {
   /**
@@ -2927,6 +2987,7 @@
    * The token for the period before the constructor name, or `null` if the
    * specified constructor is the unnamed constructor.
    */
+  @override
   Token period;
 
   /**
@@ -2940,6 +3001,7 @@
    * information, or `null` if the AST structure has not been resolved or if
    * this constructor name could not be resolved.
    */
+  @override
   ConstructorElement staticElement;
 
   /**
@@ -2995,13 +3057,14 @@
 /**
  * A continue statement.
  *
- * > continueStatement ::=
- * >     'continue' [SimpleIdentifier]? ';'
+ *    continueStatement ::=
+ *        'continue' [SimpleIdentifier]? ';'
  */
 class ContinueStatementImpl extends StatementImpl implements ContinueStatement {
   /**
    * The token representing the 'continue' keyword.
    */
+  @override
   Token continueKeyword;
 
   /**
@@ -3012,6 +3075,7 @@
   /**
    * The semicolon terminating the statement.
    */
+  @override
   Token semicolon;
 
   /**
@@ -3078,8 +3142,8 @@
 /**
  * The declaration of a single identifier.
  *
- * > declaredIdentifier ::=
- * >     [Annotation] finalConstVarOrType [SimpleIdentifier]
+ *    declaredIdentifier ::=
+ *        [Annotation] finalConstVarOrType [SimpleIdentifier]
  */
 class DeclaredIdentifierImpl extends DeclarationImpl
     implements DeclaredIdentifier {
@@ -3087,6 +3151,7 @@
    * The token representing either the 'final', 'const' or 'var' keyword, or
    * `null` if no keyword was used.
    */
+  @override
   Token keyword;
 
   /**
@@ -3180,11 +3245,11 @@
  * that are both represented by this class: named formal parameters and
  * positional formal parameters.
  *
- * > defaultFormalParameter ::=
- * >     [NormalFormalParameter] ('=' [Expression])?
- * >
- * > defaultNamedParameter ::=
- * >     [NormalFormalParameter] (':' [Expression])?
+ *    defaultFormalParameter ::=
+ *        [NormalFormalParameter] ('=' [Expression])?
+ *
+ *    defaultNamedParameter ::=
+ *        [NormalFormalParameter] (':' [Expression])?
  */
 class DefaultFormalParameterImpl extends FormalParameterImpl
     implements DefaultFormalParameter {
@@ -3196,12 +3261,14 @@
   /**
    * The kind of this parameter.
    */
+  @override
   ParameterKind kind;
 
   /**
    * The token separating the parameter from the default value, or `null` if
    * there is no default value.
    */
+  @override
   Token separator;
 
   /**
@@ -3276,18 +3343,19 @@
 /**
  * A node that represents a directive.
  *
- * > directive ::=
- * >     [ExportDirective]
- * >   | [ImportDirective]
- * >   | [LibraryDirective]
- * >   | [PartDirective]
- * >   | [PartOfDirective]
+ *    directive ::=
+ *        [ExportDirective]
+ *      | [ImportDirective]
+ *      | [LibraryDirective]
+ *      | [PartDirective]
+ *      | [PartOfDirective]
  */
 abstract class DirectiveImpl extends AnnotatedNodeImpl implements Directive {
   /**
    * The element associated with this directive, or `null` if the AST structure
    * has not been resolved or if this directive could not be resolved.
    */
+  @override
   Element element;
 
   /**
@@ -3302,13 +3370,14 @@
 /**
  * A do statement.
  *
- * > doStatement ::=
- * >     'do' [Statement] 'while' '(' [Expression] ')' ';'
+ *    doStatement ::=
+ *        'do' [Statement] 'while' '(' [Expression] ')' ';'
  */
 class DoStatementImpl extends StatementImpl implements DoStatement {
   /**
    * The token representing the 'do' keyword.
    */
+  @override
   Token doKeyword;
 
   /**
@@ -3319,6 +3388,7 @@
   /**
    * The token representing the 'while' keyword.
    */
+  @override
   Token whileKeyword;
 
   /**
@@ -3334,11 +3404,13 @@
   /**
    * The right parenthesis.
    */
+  @override
   Token rightParenthesis;
 
   /**
    * The semicolon terminating the statement.
    */
+  @override
   Token semicolon;
 
   /**
@@ -3401,8 +3473,8 @@
 /**
  * A dotted name, used in a configuration within an import or export directive.
  *
- * > dottedName ::=
- * >     [SimpleIdentifier] ('.' [SimpleIdentifier])*
+ *    dottedName ::=
+ *        [SimpleIdentifier] ('.' [SimpleIdentifier])*
  */
 class DottedNameImpl extends AstNodeImpl implements DottedName {
   /**
@@ -3442,22 +3514,24 @@
 /**
  * A floating point literal expression.
  *
- * > doubleLiteral ::=
- * >     decimalDigit+ ('.' decimalDigit*)? exponent?
- * >   | '.' decimalDigit+ exponent?
- * >
- * > exponent ::=
- * >     ('e' | 'E') ('+' | '-')? decimalDigit+
+ *    doubleLiteral ::=
+ *        decimalDigit+ ('.' decimalDigit*)? exponent?
+ *      | '.' decimalDigit+ exponent?
+ *
+ *    exponent ::=
+ *        ('e' | 'E') ('+' | '-')? decimalDigit+
  */
 class DoubleLiteralImpl extends LiteralImpl implements DoubleLiteral {
   /**
    * The token representing the literal.
    */
+  @override
   Token literal;
 
   /**
    * The value of the literal.
    */
+  @override
   double value;
 
   /**
@@ -3487,8 +3561,8 @@
  * An empty function body, which can only appear in constructors or abstract
  * methods.
  *
- * > emptyFunctionBody ::=
- * >     ';'
+ *    emptyFunctionBody ::=
+ *        ';'
  */
 class EmptyFunctionBodyImpl extends FunctionBodyImpl
     implements EmptyFunctionBody {
@@ -3496,6 +3570,7 @@
    * The token representing the semicolon that marks the end of the function
    * body.
    */
+  @override
   Token semicolon;
 
   /**
@@ -3524,8 +3599,8 @@
 /**
  * An empty statement.
  *
- * > emptyStatement ::=
- * >     ';'
+ *    emptyStatement ::=
+ *        ';'
  */
 class EmptyStatementImpl extends StatementImpl implements EmptyStatement {
   /**
@@ -3612,19 +3687,21 @@
 /**
  * The declaration of an enumeration.
  *
- * > enumType ::=
- * >     metadata 'enum' [SimpleIdentifier] '{' [SimpleIdentifier] (',' [SimpleIdentifier])* (',')? '}'
+ *    enumType ::=
+ *        metadata 'enum' [SimpleIdentifier] '{' [SimpleIdentifier] (',' [SimpleIdentifier])* (',')? '}'
  */
 class EnumDeclarationImpl extends NamedCompilationUnitMemberImpl
     implements EnumDeclaration {
   /**
    * The 'enum' keyword.
    */
+  @override
   Token enumKeyword;
 
   /**
    * The left curly bracket.
    */
+  @override
   Token leftBracket;
 
   /**
@@ -3635,6 +3712,7 @@
   /**
    * The right curly bracket.
    */
+  @override
   Token rightBracket;
 
   /**
@@ -3702,8 +3780,8 @@
 /**
  * An export directive.
  *
- * > exportDirective ::=
- * >     [Annotation] 'export' [StringLiteral] [Combinator]* ';'
+ *    exportDirective ::=
+ *        [Annotation] 'export' [StringLiteral] [Combinator]* ';'
  */
 class ExportDirectiveImpl extends NamespaceDirectiveImpl
     implements ExportDirective {
@@ -3754,8 +3832,8 @@
 /**
  * A function body consisting of a single expression.
  *
- * > expressionFunctionBody ::=
- * >     'async'? '=>' [Expression] ';'
+ *    expressionFunctionBody ::=
+ *        'async'? '=>' [Expression] ';'
  */
 class ExpressionFunctionBodyImpl extends FunctionBodyImpl
     implements ExpressionFunctionBody {
@@ -3763,12 +3841,14 @@
    * The token representing the 'async' keyword, or `null` if there is no such
    * keyword.
    */
+  @override
   Token keyword;
 
   /**
    * The token introducing the expression that represents the body of the
    * function.
    */
+  @override
   Token functionDefinition;
 
   /**
@@ -3779,6 +3859,7 @@
   /**
    * The semicolon terminating the statement.
    */
+  @override
   Token semicolon;
 
   /**
@@ -3840,22 +3921,24 @@
 /**
  * A node that represents an expression.
  *
- * > expression ::=
- * >     [AssignmentExpression]
- * >   | [ConditionalExpression] cascadeSection*
- * >   | [ThrowExpression]
+ *    expression ::=
+ *        [AssignmentExpression]
+ *      | [ConditionalExpression] cascadeSection*
+ *      | [ThrowExpression]
  */
 abstract class ExpressionImpl extends AstNodeImpl implements Expression {
   /**
    * The static type of this expression, or `null` if the AST structure has not
    * been resolved.
    */
+  @override
   DartType staticType;
 
   /**
    * The propagated type of this expression, or `null` if type propagation has
    * not been performed on the AST structure.
    */
+  @override
   DartType propagatedType;
 
   /**
@@ -3939,8 +4022,8 @@
 /**
  * An expression used as a statement.
  *
- * > expressionStatement ::=
- * >     [Expression]? ';'
+ *    expressionStatement ::=
+ *        [Expression]? ';'
  */
 class ExpressionStatementImpl extends StatementImpl
     implements ExpressionStatement {
@@ -3953,6 +4036,7 @@
    * The semicolon terminating the statement, or `null` if the expression is a
    * function expression and therefore isn't followed by a semicolon.
    */
+  @override
   Token semicolon;
 
   /**
@@ -4000,13 +4084,14 @@
 /**
  * The "extends" clause in a class declaration.
  *
- * > extendsClause ::=
- * >     'extends' [TypeName]
+ *    extendsClause ::=
+ *        'extends' [TypeName]
  */
 class ExtendsClauseImpl extends AstNodeImpl implements ExtendsClause {
   /**
    * The token representing the 'extends' keyword.
    */
+  @override
   Token extendsKeyword;
 
   /**
@@ -4051,14 +4136,15 @@
 /**
  * The declaration of one or more fields of the same type.
  *
- * > fieldDeclaration ::=
- * >     'static'? [VariableDeclarationList] ';'
+ *    fieldDeclaration ::=
+ *        'static'? [VariableDeclarationList] ';'
  */
 class FieldDeclarationImpl extends ClassMemberImpl implements FieldDeclaration {
   /**
    * The token representing the 'static' keyword, or `null` if the fields are
    * not static.
    */
+  @override
   Token staticKeyword;
 
   /**
@@ -4069,6 +4155,7 @@
   /**
    * The semicolon terminating the declaration.
    */
+  @override
   Token semicolon;
 
   /**
@@ -4125,9 +4212,9 @@
 /**
  * A field formal parameter.
  *
- * > fieldFormalParameter ::=
- * >     ('final' [TypeName] | 'const' [TypeName] | 'var' | [TypeName])?
- * >     'this' '.' [SimpleIdentifier] ([TypeParameterList]? [FormalParameterList])?
+ *    fieldFormalParameter ::=
+ *        ('final' [TypeName] | 'const' [TypeName] | 'var' | [TypeName])?
+ *        'this' '.' [SimpleIdentifier] ([TypeParameterList]? [FormalParameterList])?
  */
 class FieldFormalParameterImpl extends NormalFormalParameterImpl
     implements FieldFormalParameter {
@@ -4135,6 +4222,7 @@
    * The token representing either the 'final', 'const' or 'var' keyword, or
    * `null` if no keyword was used.
    */
+  @override
   Token keyword;
 
   /**
@@ -4146,11 +4234,13 @@
   /**
    * The token representing the 'this' keyword.
    */
+  @override
   Token thisKeyword;
 
   /**
    * The token representing the period.
    */
+  @override
   Token period;
 
   /**
@@ -4267,25 +4357,28 @@
 /**
  * A for-each statement.
  *
- * > forEachStatement ::=
- * >     'await'? 'for' '(' [DeclaredIdentifier] 'in' [Expression] ')' [Block]
- * >   | 'await'? 'for' '(' [SimpleIdentifier] 'in' [Expression] ')' [Block]
+ *    forEachStatement ::=
+ *        'await'? 'for' '(' [DeclaredIdentifier] 'in' [Expression] ')' [Block]
+ *      | 'await'? 'for' '(' [SimpleIdentifier] 'in' [Expression] ')' [Block]
  */
 class ForEachStatementImpl extends StatementImpl implements ForEachStatement {
   /**
    * The token representing the 'await' keyword, or `null` if there is no
    * 'await' keyword.
    */
+  @override
   Token awaitKeyword;
 
   /**
    * The token representing the 'for' keyword.
    */
+  @override
   Token forKeyword;
 
   /**
    * The left parenthesis.
    */
+  @override
   Token leftParenthesis;
 
   /**
@@ -4302,6 +4395,7 @@
   /**
    * The token representing the 'in' keyword.
    */
+  @override
   Token inKeyword;
 
   /**
@@ -4312,6 +4406,7 @@
   /**
    * The right parenthesis.
    */
+  @override
   Token rightParenthesis;
 
   /**
@@ -4422,9 +4517,9 @@
 /**
  * A node representing a parameter to a function.
  *
- * > formalParameter ::=
- * >     [NormalFormalParameter]
- * >   | [DefaultFormalParameter]
+ *    formalParameter ::=
+ *        [NormalFormalParameter]
+ *      | [DefaultFormalParameter]
  */
 abstract class FormalParameterImpl extends AstNodeImpl
     implements FormalParameter {
@@ -4448,29 +4543,30 @@
  * flattened into a single list, which can have any or all kinds of parameters
  * (normal, named, and positional) in any order.
  *
- * > formalParameterList ::=
- * >     '(' ')'
- * >   | '(' normalFormalParameters (',' optionalFormalParameters)? ')'
- * >   | '(' optionalFormalParameters ')'
- * >
- * > normalFormalParameters ::=
- * >     [NormalFormalParameter] (',' [NormalFormalParameter])*
- * >
- * > optionalFormalParameters ::=
- * >     optionalPositionalFormalParameters
- * >   | namedFormalParameters
- * >
- * > optionalPositionalFormalParameters ::=
- * >     '[' [DefaultFormalParameter] (',' [DefaultFormalParameter])* ']'
- * >
- * > namedFormalParameters ::=
- * >     '{' [DefaultFormalParameter] (',' [DefaultFormalParameter])* '}'
+ *    formalParameterList ::=
+ *        '(' ')'
+ *      | '(' normalFormalParameters (',' optionalFormalParameters)? ')'
+ *      | '(' optionalFormalParameters ')'
+ *
+ *    normalFormalParameters ::=
+ *        [NormalFormalParameter] (',' [NormalFormalParameter])*
+ *
+ *    optionalFormalParameters ::=
+ *        optionalPositionalFormalParameters
+ *      | namedFormalParameters
+ *
+ *    optionalPositionalFormalParameters ::=
+ *        '[' [DefaultFormalParameter] (',' [DefaultFormalParameter])* ']'
+ *
+ *    namedFormalParameters ::=
+ *        '{' [DefaultFormalParameter] (',' [DefaultFormalParameter])* '}'
  */
 class FormalParameterListImpl extends AstNodeImpl
     implements FormalParameterList {
   /**
    * The left parenthesis.
    */
+  @override
   Token leftParenthesis;
 
   /**
@@ -4482,17 +4578,20 @@
    * The left square bracket ('[') or left curly brace ('{') introducing the
    * optional parameters, or `null` if there are no optional parameters.
    */
+  @override
   Token leftDelimiter;
 
   /**
    * The right square bracket (']') or right curly brace ('}') terminating the
    * optional parameters, or `null` if there are no optional parameters.
    */
+  @override
   Token rightDelimiter;
 
   /**
    * The right parenthesis.
    */
+  @override
   Token rightParenthesis;
 
   /**
@@ -4555,25 +4654,27 @@
 /**
  * A for statement.
  *
- * > forStatement ::=
- * >     'for' '(' forLoopParts ')' [Statement]
- * >
- * > forLoopParts ::=
- * >     forInitializerStatement ';' [Expression]? ';' [Expression]?
- * >
- * > forInitializerStatement ::=
- * >     [DefaultFormalParameter]
- * >   | [Expression]?
+ *    forStatement ::=
+ *        'for' '(' forLoopParts ')' [Statement]
+ *
+ *    forLoopParts ::=
+ *        forInitializerStatement ';' [Expression]? ';' [Expression]?
+ *
+ *    forInitializerStatement ::=
+ *        [DefaultFormalParameter]
+ *      | [Expression]?
  */
 class ForStatementImpl extends StatementImpl implements ForStatement {
   /**
    * The token representing the 'for' keyword.
    */
+  @override
   Token forKeyword;
 
   /**
    * The left parenthesis.
    */
+  @override
   Token leftParenthesis;
 
   /**
@@ -4593,6 +4694,7 @@
   /**
    * The semicolon separating the initializer and the condition.
    */
+  @override
   Token leftSeparator;
 
   /**
@@ -4604,6 +4706,7 @@
   /**
    * The semicolon separating the condition and the updater.
    */
+  @override
   Token rightSeparator;
 
   /**
@@ -4614,6 +4717,7 @@
   /**
    * The right parenthesis.
    */
+  @override
   Token rightParenthesis;
 
   /**
@@ -4715,10 +4819,10 @@
 /**
  * A node representing the body of a function or method.
  *
- * > functionBody ::=
- * >     [BlockFunctionBody]
- * >   | [EmptyFunctionBody]
- * >   | [ExpressionFunctionBody]
+ *    functionBody ::=
+ *        [BlockFunctionBody]
+ *      | [EmptyFunctionBody]
+ *      | [ExpressionFunctionBody]
  */
 abstract class FunctionBodyImpl extends AstNodeImpl implements FunctionBody {
   /**
@@ -4731,28 +4835,33 @@
   /**
    * Return `true` if this function body is asynchronous.
    */
+  @override
   bool get isAsynchronous => false;
 
   /**
    * Return `true` if this function body is a generator.
    */
+  @override
   bool get isGenerator => false;
 
   /**
    * Return `true` if this function body is synchronous.
    */
+  @override
   bool get isSynchronous => true;
 
   /**
    * Return the token representing the 'async' or 'sync' keyword, or `null` if
    * there is no such keyword.
    */
+  @override
   Token get keyword => null;
 
   /**
    * Return the star following the 'async' or 'sync' keyword, or `null` if there
    * is no star.
    */
+  @override
   Token get star => null;
 
   @override
@@ -4775,12 +4884,12 @@
 /**
  * A top-level declaration.
  *
- * > functionDeclaration ::=
- * >     'external' functionSignature
- * >   | functionSignature [FunctionBody]
- * >
- * > functionSignature ::=
- * >     [Type]? ('get' | 'set')? [SimpleIdentifier] [FormalParameterList]
+ *    functionDeclaration ::=
+ *        'external' functionSignature
+ *      | functionSignature [FunctionBody]
+ *
+ *    functionSignature ::=
+ *        [Type]? ('get' | 'set')? [SimpleIdentifier] [FormalParameterList]
  */
 class FunctionDeclarationImpl extends NamedCompilationUnitMemberImpl
     implements FunctionDeclaration {
@@ -4788,6 +4897,7 @@
    * The token representing the 'external' keyword, or `null` if this is not an
    * external function.
    */
+  @override
   Token externalKeyword;
 
   /**
@@ -4799,6 +4909,7 @@
    * The token representing the 'get' or 'set' keyword, or `null` if this is a
    * function declaration rather than a property declaration.
    */
+  @override
   Token propertyKeyword;
 
   /**
@@ -4940,8 +5051,8 @@
 /**
  * A function expression.
  *
- * > functionExpression ::=
- * >     [TypeParameterList]? [FormalParameterList] [FunctionBody]
+ *    functionExpression ::=
+ *        [TypeParameterList]? [FormalParameterList] [FunctionBody]
  */
 class FunctionExpressionImpl extends ExpressionImpl
     implements FunctionExpression {
@@ -4965,6 +5076,7 @@
    * The element associated with the function, or `null` if the AST structure
    * has not been resolved.
    */
+  @override
   ExecutableElement element;
 
   /**
@@ -5051,8 +5163,8 @@
  * [MethodInvocation] nodes. Invocations of getters and setters are represented
  * by either [PrefixedIdentifier] or [PropertyAccess] nodes.
  *
- * > functionExpressionInvocation ::=
- * >     [Expression] [TypeArgumentList]? [ArgumentList]
+ *    functionExpressionInvocation ::=
+ *        [Expression] [TypeArgumentList]? [ArgumentList]
  */
 class FunctionExpressionInvocationImpl extends InvocationExpressionImpl
     implements FunctionExpressionInvocation {
@@ -5066,6 +5178,7 @@
    * information, or `null` if the AST structure has not been resolved or the
    * function could not be resolved.
    */
+  @override
   ExecutableElement staticElement;
 
   /**
@@ -5073,6 +5186,7 @@
    * type information, or `null` if the AST structure has not been resolved or
    * the function could not be resolved.
    */
+  @override
   ExecutableElement propagatedElement;
 
   /**
@@ -5128,11 +5242,11 @@
 /**
  * A function type alias.
  *
- * > functionTypeAlias ::=
- * >     functionPrefix [TypeParameterList]? [FormalParameterList] ';'
- * >
- * > functionPrefix ::=
- * >     [TypeName]? [SimpleIdentifier]
+ *    functionTypeAlias ::=
+ *        functionPrefix [TypeParameterList]? [FormalParameterList] ';'
+ *
+ *    functionPrefix ::=
+ *        [TypeName]? [SimpleIdentifier]
  */
 class FunctionTypeAliasImpl extends TypeAliasImpl implements FunctionTypeAlias {
   /**
@@ -5227,8 +5341,8 @@
 /**
  * A function-typed formal parameter.
  *
- * > functionSignature ::=
- * >     [TypeName]? [SimpleIdentifier] [TypeParameterList]? [FormalParameterList]
+ *    functionSignature ::=
+ *        [TypeName]? [SimpleIdentifier] [TypeParameterList]? [FormalParameterList]
  */
 class FunctionTypedFormalParameterImpl extends NormalFormalParameterImpl
     implements FunctionTypedFormalParameter {
@@ -5330,8 +5444,8 @@
  * A combinator that restricts the names being imported to those that are not in
  * a given list.
  *
- * > hideCombinator ::=
- * >     'hide' [SimpleIdentifier] (',' [SimpleIdentifier])*
+ *    hideCombinator ::=
+ *        'hide' [SimpleIdentifier] (',' [SimpleIdentifier])*
  */
 class HideCombinatorImpl extends CombinatorImpl implements HideCombinator {
   /**
@@ -5370,9 +5484,9 @@
 /**
  * A node that represents an identifier.
  *
- * > identifier ::=
- * >     [SimpleIdentifier]
- * >   | [PrefixedIdentifier]
+ *    identifier ::=
+ *        [SimpleIdentifier]
+ *      | [PrefixedIdentifier]
  */
 abstract class IdentifierImpl extends ExpressionImpl implements Identifier {
   /**
@@ -5391,18 +5505,20 @@
 /**
  * An if statement.
  *
- * > ifStatement ::=
- * >     'if' '(' [Expression] ')' [Statement] ('else' [Statement])?
+ *    ifStatement ::=
+ *        'if' '(' [Expression] ')' [Statement] ('else' [Statement])?
  */
 class IfStatementImpl extends StatementImpl implements IfStatement {
   /**
    * The token representing the 'if' keyword.
    */
+  @override
   Token ifKeyword;
 
   /**
    * The left parenthesis.
    */
+  @override
   Token leftParenthesis;
 
   /**
@@ -5413,6 +5529,7 @@
   /**
    * The right parenthesis.
    */
+  @override
   Token rightParenthesis;
 
   /**
@@ -5424,6 +5541,7 @@
    * The token representing the 'else' keyword, or `null` if there is no else
    * statement.
    */
+  @override
   Token elseKeyword;
 
   /**
@@ -5508,13 +5626,14 @@
 /**
  * The "implements" clause in an class declaration.
  *
- * > implementsClause ::=
- * >     'implements' [TypeName] (',' [TypeName])*
+ *    implementsClause ::=
+ *        'implements' [TypeName] (',' [TypeName])*
  */
 class ImplementsClauseImpl extends AstNodeImpl implements ImplementsClause {
   /**
    * The token representing the 'implements' keyword.
    */
+  @override
   Token implementsKeyword;
 
   /**
@@ -5556,9 +5675,9 @@
 /**
  * An import directive.
  *
- * > importDirective ::=
- * >     [Annotation] 'import' [StringLiteral] ('as' identifier)? [Combinator]* ';'
- * >   | [Annotation] 'import' [StringLiteral] 'deferred' 'as' identifier [Combinator]* ';'
+ *    importDirective ::=
+ *        [Annotation] 'import' [StringLiteral] ('as' identifier)? [Combinator]* ';'
+ *      | [Annotation] 'import' [StringLiteral] 'deferred' 'as' identifier [Combinator]* ';'
  */
 class ImportDirectiveImpl extends NamespaceDirectiveImpl
     implements ImportDirective {
@@ -5572,6 +5691,7 @@
    * The token representing the 'as' keyword, or `null` if the imported names are
    * not prefixed.
    */
+  @override
   Token asKeyword;
 
   /**
@@ -5647,8 +5767,8 @@
 /**
  * An index expression.
  *
- * > indexExpression ::=
- * >     [Expression] '[' [Expression] ']'
+ *    indexExpression ::=
+ *        [Expression] '[' [Expression] ']'
  */
 class IndexExpressionImpl extends ExpressionImpl implements IndexExpression {
   /**
@@ -5661,11 +5781,13 @@
    * The period ("..") before a cascaded index expression, or `null` if this
    * index expression is not part of a cascade expression.
    */
+  @override
   Token period;
 
   /**
    * The left square bracket.
    */
+  @override
   Token leftBracket;
 
   /**
@@ -5676,6 +5798,7 @@
   /**
    * The right square bracket.
    */
+  @override
   Token rightBracket;
 
   /**
@@ -5683,6 +5806,7 @@
    * target, or `null` if the AST structure has not been resolved or if the
    * operator could not be resolved.
    */
+  @override
   MethodElement staticElement;
 
   /**
@@ -5690,6 +5814,8 @@
    * the target, or `null` if the AST structure has not been resolved or if the
    * operator could not be resolved.
    */
+
+  @override
   MethodElement propagatedElement;
 
   /**
@@ -5860,8 +5986,8 @@
 /**
  * An instance creation expression.
  *
- * > newExpression ::=
- * >     ('new' | 'const') [TypeName] ('.' [SimpleIdentifier])? [ArgumentList]
+ *    newExpression ::=
+ *        ('new' | 'const') [TypeName] ('.' [SimpleIdentifier])? [ArgumentList]
  */
 class InstanceCreationExpressionImpl extends ExpressionImpl
     implements InstanceCreationExpression {
@@ -5869,6 +5995,7 @@
    * The 'new' or 'const' keyword used to indicate how an object should be
    * created.
    */
+  @override
   Token keyword;
 
   /**
@@ -5886,6 +6013,7 @@
    * information, or `null` if the AST structure has not been resolved or if the
    * constructor could not be resolved.
    */
+  @override
   ConstructorElement staticElement;
 
   /**
@@ -5946,26 +6074,28 @@
 /**
  * An integer literal expression.
  *
- * > integerLiteral ::=
- * >     decimalIntegerLiteral
- * >   | hexadecimalIntegerLiteral
- * >
- * > decimalIntegerLiteral ::=
- * >     decimalDigit+
- * >
- * > hexadecimalIntegerLiteral ::=
- * >     '0x' hexadecimalDigit+
- * >   | '0X' hexadecimalDigit+
+ *    integerLiteral ::=
+ *        decimalIntegerLiteral
+ *      | hexadecimalIntegerLiteral
+ *
+ *    decimalIntegerLiteral ::=
+ *        decimalDigit+
+ *
+ *    hexadecimalIntegerLiteral ::=
+ *        '0x' hexadecimalDigit+
+ *      | '0X' hexadecimalDigit+
  */
 class IntegerLiteralImpl extends LiteralImpl implements IntegerLiteral {
   /**
    * The token representing the literal.
    */
+  @override
   Token literal;
 
   /**
    * The value of the literal.
    */
+  @override
   int value = 0;
 
   /**
@@ -5994,9 +6124,9 @@
 /**
  * A node within a [StringInterpolation].
  *
- * > interpolationElement ::=
- * >     [InterpolationExpression]
- * >   | [InterpolationString]
+ *    interpolationElement ::=
+ *        [InterpolationExpression]
+ *      | [InterpolationString]
  */
 abstract class InterpolationElementImpl extends AstNodeImpl
     implements InterpolationElement {}
@@ -6004,9 +6134,9 @@
 /**
  * An expression embedded in a string interpolation.
  *
- * > interpolationExpression ::=
- * >     '$' [SimpleIdentifier]
- * >   | '$' '{' [Expression] '}'
+ *    interpolationExpression ::=
+ *        '$' [SimpleIdentifier]
+ *      | '$' '{' [Expression] '}'
  */
 class InterpolationExpressionImpl extends InterpolationElementImpl
     implements InterpolationExpression {
@@ -6015,6 +6145,7 @@
    * expression is a simple identifier or '${' if the expression is a full
    * expression.
    */
+  @override
   Token leftBracket;
 
   /**
@@ -6026,6 +6157,7 @@
    * The right curly bracket, or `null` if the expression is an identifier
    * without brackets.
    */
+  @override
   Token rightBracket;
 
   /**
@@ -6073,19 +6205,21 @@
 /**
  * A non-empty substring of an interpolated string.
  *
- * > interpolationString ::=
- * >     characters
+ *    interpolationString ::=
+ *        characters
  */
 class InterpolationStringImpl extends InterpolationElementImpl
     implements InterpolationString {
   /**
    * The characters that will be added to the string.
    */
+  @override
   Token contents;
 
   /**
    * The value of the literal.
    */
+  @override
   String value;
 
   /**
@@ -6158,7 +6292,6 @@
   @override
   ArgumentList get argumentList => _argumentList;
 
-  @override
   void set argumentList(ArgumentList argumentList) {
     _argumentList = _becomeParentOf(argumentList);
   }
@@ -6166,7 +6299,6 @@
   @override
   TypeArgumentList get typeArguments => _typeArguments;
 
-  @override
   void set typeArguments(TypeArgumentList typeArguments) {
     _typeArguments = _becomeParentOf(typeArguments);
   }
@@ -6175,8 +6307,8 @@
 /**
  * An is expression.
  *
- * > isExpression ::=
- * >     [Expression] 'is' '!'? [TypeName]
+ *    isExpression ::=
+ *        [Expression] 'is' '!'? [TypeName]
  */
 class IsExpressionImpl extends ExpressionImpl implements IsExpression {
   /**
@@ -6187,11 +6319,13 @@
   /**
    * The is operator.
    */
+  @override
   Token isOperator;
 
   /**
    * The not operator, or `null` if the sense of the test is not negated.
    */
+  @override
   Token notOperator;
 
   /**
@@ -6254,8 +6388,8 @@
 /**
  * A statement that has a label associated with them.
  *
- * > labeledStatement ::=
- * >    [Label]+ [Statement]
+ *    labeledStatement ::=
+ *       [Label]+ [Statement]
  */
 class LabeledStatementImpl extends StatementImpl implements LabeledStatement {
   /**
@@ -6319,8 +6453,8 @@
 /**
  * A label on either a [LabeledStatement] or a [NamedExpression].
  *
- * > label ::=
- * >     [SimpleIdentifier] ':'
+ *    label ::=
+ *        [SimpleIdentifier] ':'
  */
 class LabelImpl extends AstNodeImpl implements Label {
   /**
@@ -6331,6 +6465,7 @@
   /**
    * The colon that separates the label from the statement.
    */
+  @override
   Token colon;
 
   /**
@@ -6369,13 +6504,14 @@
 /**
  * A library directive.
  *
- * > libraryDirective ::=
- * >     [Annotation] 'library' [Identifier] ';'
+ *    libraryDirective ::=
+ *        [Annotation] 'library' [Identifier] ';'
  */
 class LibraryDirectiveImpl extends DirectiveImpl implements LibraryDirective {
   /**
    * The token representing the 'library' keyword.
    */
+  @override
   Token libraryKeyword;
 
   /**
@@ -6386,6 +6522,7 @@
   /**
    * The semicolon terminating the directive.
    */
+  @override
   Token semicolon;
 
   /**
@@ -6433,8 +6570,8 @@
 /**
  * The identifier for a library.
  *
- * > libraryIdentifier ::=
- * >     [SimpleIdentifier] ('.' [SimpleIdentifier])*
+ *    libraryIdentifier ::=
+ *        [SimpleIdentifier] ('.' [SimpleIdentifier])*
  */
 class LibraryIdentifierImpl extends IdentifierImpl
     implements LibraryIdentifier {
@@ -6502,13 +6639,14 @@
 /**
  * A list literal.
  *
- * > listLiteral ::=
- * >     'const'? ('<' [TypeName] '>')? '[' ([Expression] ','?)? ']'
+ *    listLiteral ::=
+ *        'const'? ('<' [TypeName] '>')? '[' ([Expression] ','?)? ']'
  */
 class ListLiteralImpl extends TypedLiteralImpl implements ListLiteral {
   /**
    * The left square bracket.
    */
+  @override
   Token leftBracket;
 
   /**
@@ -6519,6 +6657,7 @@
   /**
    * The right square bracket.
    */
+  @override
   Token rightBracket;
 
   /**
@@ -6571,14 +6710,14 @@
 /**
  * A node that represents a literal expression.
  *
- * > literal ::=
- * >     [BooleanLiteral]
- * >   | [DoubleLiteral]
- * >   | [IntegerLiteral]
- * >   | [ListLiteral]
- * >   | [MapLiteral]
- * >   | [NullLiteral]
- * >   | [StringLiteral]
+ *    literal ::=
+ *        [BooleanLiteral]
+ *      | [DoubleLiteral]
+ *      | [IntegerLiteral]
+ *      | [ListLiteral]
+ *      | [MapLiteral]
+ *      | [NullLiteral]
+ *      | [StringLiteral]
  */
 abstract class LiteralImpl extends ExpressionImpl implements Literal {
   @override
@@ -6608,8 +6747,8 @@
 /**
  * A single key/value pair in a map literal.
  *
- * > mapLiteralEntry ::=
- * >     [Expression] ':' [Expression]
+ *    mapLiteralEntry ::=
+ *        [Expression] ':' [Expression]
  */
 class MapLiteralEntryImpl extends AstNodeImpl implements MapLiteralEntry {
   /**
@@ -6620,6 +6759,7 @@
   /**
    * The colon that separates the key from the value.
    */
+  @override
   Token separator;
 
   /**
@@ -6674,14 +6814,15 @@
 /**
  * A literal map.
  *
- * > mapLiteral ::=
- * >     'const'? ('<' [TypeName] (',' [TypeName])* '>')?
- * >     '{' ([MapLiteralEntry] (',' [MapLiteralEntry])* ','?)? '}'
+ *    mapLiteral ::=
+ *        'const'? ('<' [TypeName] (',' [TypeName])* '>')?
+ *        '{' ([MapLiteralEntry] (',' [MapLiteralEntry])* ','?)? '}'
  */
 class MapLiteralImpl extends TypedLiteralImpl implements MapLiteral {
   /**
    * The left curly bracket.
    */
+  @override
   Token leftBracket;
 
   /**
@@ -6692,6 +6833,7 @@
   /**
    * The right curly bracket.
    */
+  @override
   Token rightBracket;
 
   /**
@@ -6743,16 +6885,16 @@
 /**
  * A method declaration.
  *
- * > methodDeclaration ::=
- * >     methodSignature [FunctionBody]
- * >
- * > methodSignature ::=
- * >     'external'? ('abstract' | 'static')? [Type]? ('get' | 'set')?
- * >     methodName [TypeParameterList] [FormalParameterList]
- * >
- * > methodName ::=
- * >     [SimpleIdentifier]
- * >   | 'operator' [SimpleIdentifier]
+ *    methodDeclaration ::=
+ *        methodSignature [FunctionBody]
+ *
+ *    methodSignature ::=
+ *        'external'? ('abstract' | 'static')? [Type]? ('get' | 'set')?
+ *        methodName [TypeParameterList] [FormalParameterList]
+ *
+ *    methodName ::=
+ *        [SimpleIdentifier]
+ *      | 'operator' [SimpleIdentifier]
  */
 class MethodDeclarationImpl extends ClassMemberImpl
     implements MethodDeclaration {
@@ -6760,12 +6902,14 @@
    * The token for the 'external' keyword, or `null` if the constructor is not
    * external.
    */
+  @override
   Token externalKeyword;
 
   /**
    * The token representing the 'abstract' or 'static' keyword, or `null` if
    * neither modifier was specified.
    */
+  @override
   Token modifierKeyword;
 
   /**
@@ -6777,12 +6921,14 @@
    * The token representing the 'get' or 'set' keyword, or `null` if this is a
    * method declaration rather than a property declaration.
    */
+  @override
   Token propertyKeyword;
 
   /**
    * The token representing the 'operator' keyword, or `null` if this method
    * does not declare an operator.
    */
+  @override
   Token operatorKeyword;
 
   /**
@@ -6962,8 +7108,8 @@
  * [FunctionExpressionInvocation] nodes. Invocations of getters and setters are
  * represented by either [PrefixedIdentifier] or [PropertyAccess] nodes.
  *
- * > methodInvocation ::=
- * >     ([Expression] '.')? [SimpleIdentifier] [TypeArgumentList]? [ArgumentList]
+ *    methodInvocation ::=
+ *        ([Expression] '.')? [SimpleIdentifier] [TypeArgumentList]? [ArgumentList]
  */
 class MethodInvocationImpl extends InvocationExpressionImpl
     implements MethodInvocation {
@@ -6979,6 +7125,7 @@
    * period ('.'). In a cascade section this will be the cascade operator
    * ('..').
    */
+  @override
   Token operator;
 
   /**
@@ -7108,8 +7255,8 @@
  * An expression that has a name associated with it. They are used in method
  * invocations when there are named parameters.
  *
- * > namedExpression ::=
- * >     [Label] [Expression]
+ *    namedExpression ::=
+ *        [Label] [Expression]
  */
 class NamedExpressionImpl extends ExpressionImpl implements NamedExpression {
   /**
@@ -7181,15 +7328,16 @@
 /**
  * A node that represents a directive that impacts the namespace of a library.
  *
- * > directive ::=
- * >     [ExportDirective]
- * >   | [ImportDirective]
+ *    directive ::=
+ *        [ExportDirective]
+ *      | [ImportDirective]
  */
 abstract class NamespaceDirectiveImpl extends UriBasedDirectiveImpl
     implements NamespaceDirective {
   /**
    * The token representing the 'import' or 'export' keyword.
    */
+  @override
   Token keyword;
 
   /**
@@ -7206,6 +7354,7 @@
   /**
    * The semicolon terminating the directive.
    */
+  @override
   Token semicolon;
 
   /**
@@ -7246,13 +7395,14 @@
 /**
  * The "native" clause in an class declaration.
  *
- * > nativeClause ::=
- * >     'native' [StringLiteral]
+ *    nativeClause ::=
+ *        'native' [StringLiteral]
  */
 class NativeClauseImpl extends AstNodeImpl implements NativeClause {
   /**
    * The token representing the 'native' keyword.
    */
+  @override
   Token nativeKeyword;
 
   /**
@@ -7298,14 +7448,15 @@
  * A function body that consists of a native keyword followed by a string
  * literal.
  *
- * > nativeFunctionBody ::=
- * >     'native' [SimpleStringLiteral] ';'
+ *    nativeFunctionBody ::=
+ *        'native' [SimpleStringLiteral] ';'
  */
 class NativeFunctionBodyImpl extends FunctionBodyImpl
     implements NativeFunctionBody {
   /**
    * The token representing 'native' that marks the start of the function body.
    */
+  @override
   Token nativeKeyword;
 
   /**
@@ -7317,6 +7468,7 @@
    * The token representing the semicolon that marks the end of the function
    * body.
    */
+  @override
   Token semicolon;
 
   /**
@@ -7366,6 +7518,7 @@
   /**
    * The node that is the parent of each of the elements in the list.
    */
+  @override
   AstNodeImpl owner;
 
   /**
@@ -7480,10 +7633,10 @@
 /**
  * A formal parameter that is required (is not optional).
  *
- * > normalFormalParameter ::=
- * >     [FunctionTypedFormalParameter]
- * >   | [FieldFormalParameter]
- * >   | [SimpleFormalParameter]
+ *    normalFormalParameter ::=
+ *        [FunctionTypedFormalParameter]
+ *      | [FieldFormalParameter]
+ *      | [SimpleFormalParameter]
  */
 abstract class NormalFormalParameterImpl extends FormalParameterImpl
     implements NormalFormalParameter {
@@ -7600,8 +7753,8 @@
 /**
  * A null literal expression.
  *
- * > nullLiteral ::=
- * >     'null'
+ *    nullLiteral ::=
+ *        'null'
  */
 class NullLiteralImpl extends LiteralImpl implements NullLiteral {
   /**
@@ -7635,8 +7788,8 @@
 /**
  * A parenthesized expression.
  *
- * > parenthesizedExpression ::=
- * >     '(' [Expression] ')'
+ *    parenthesizedExpression ::=
+ *        '(' [Expression] ')'
  */
 class ParenthesizedExpressionImpl extends ExpressionImpl
     implements ParenthesizedExpression {
@@ -7698,18 +7851,20 @@
 /**
  * A part directive.
  *
- * > partDirective ::=
- * >     [Annotation] 'part' [StringLiteral] ';'
+ *    partDirective ::=
+ *        [Annotation] 'part' [StringLiteral] ';'
  */
 class PartDirectiveImpl extends UriBasedDirectiveImpl implements PartDirective {
   /**
    * The token representing the 'part' keyword.
    */
+  @override
   Token partKeyword;
 
   /**
    * The semicolon terminating the directive.
    */
+  @override
   Token semicolon;
 
   /**
@@ -7744,18 +7899,20 @@
 /**
  * A part-of directive.
  *
- * > partOfDirective ::=
- * >     [Annotation] 'part' 'of' [Identifier] ';'
+ *    partOfDirective ::=
+ *        [Annotation] 'part' 'of' [Identifier] ';'
  */
 class PartOfDirectiveImpl extends DirectiveImpl implements PartOfDirective {
   /**
    * The token representing the 'part' keyword.
    */
+  @override
   Token partKeyword;
 
   /**
    * The token representing the 'of' keyword.
    */
+  @override
   Token ofKeyword;
 
   /**
@@ -7766,6 +7923,7 @@
   /**
    * The semicolon terminating the directive.
    */
+  @override
   Token semicolon;
 
   /**
@@ -7821,8 +7979,8 @@
 /**
  * A postfix unary expression.
  *
- * > postfixExpression ::=
- * >     [Expression] [Token]
+ *    postfixExpression ::=
+ *        [Expression] [Token]
  */
 class PostfixExpressionImpl extends ExpressionImpl
     implements PostfixExpression {
@@ -7834,6 +7992,7 @@
   /**
    * The postfix operator being applied to the operand.
    */
+  @override
   Token operator;
 
   /**
@@ -7842,6 +8001,7 @@
    * the operator is not user definable, or if the operator could not be
    * resolved.
    */
+  @override
   MethodElement propagatedElement;
 
   /**
@@ -7849,6 +8009,7 @@
    * operand, or `null` if the AST structure has not been resolved, if the
    * operator is not user definable, or if the operator could not be resolved.
    */
+  @override
   MethodElement staticElement;
 
   /**
@@ -7935,8 +8096,8 @@
  * An identifier that is prefixed or an access to an object property where the
  * target of the property access is a simple identifier.
  *
- * > prefixedIdentifier ::=
- * >     [SimpleIdentifier] '.' [SimpleIdentifier]
+ *    prefixedIdentifier ::=
+ *        [SimpleIdentifier] '.' [SimpleIdentifier]
  */
 class PrefixedIdentifierImpl extends IdentifierImpl
     implements PrefixedIdentifier {
@@ -8048,8 +8209,8 @@
 /**
  * A prefix unary expression.
  *
- * > prefixExpression ::=
- * >     [Token] [Expression]
+ *    prefixExpression ::=
+ *        [Token] [Expression]
  */
 class PrefixExpressionImpl extends ExpressionImpl implements PrefixExpression {
   /**
@@ -8163,8 +8324,8 @@
  * as [PrefixedIdentifier] nodes in cases where the target is also a simple
  * identifier.
  *
- * > propertyAccess ::=
- * >     [Expression] '.' [SimpleIdentifier]
+ *    propertyAccess ::=
+ *        [Expression] '.' [SimpleIdentifier]
  */
 class PropertyAccessImpl extends ExpressionImpl implements PropertyAccess {
   /**
@@ -8261,8 +8422,8 @@
  * The invocation of a constructor in the same class from within a constructor's
  * initialization list.
  *
- * > redirectingConstructorInvocation ::=
- * >     'this' ('.' identifier)? arguments
+ *    redirectingConstructorInvocation ::=
+ *        'this' ('.' identifier)? arguments
  */
 class RedirectingConstructorInvocationImpl extends ConstructorInitializerImpl
     implements RedirectingConstructorInvocation {
@@ -8349,8 +8510,8 @@
 /**
  * A rethrow expression.
  *
- * > rethrowExpression ::=
- * >     'rethrow'
+ *    rethrowExpression ::=
+ *        'rethrow'
  */
 class RethrowExpressionImpl extends ExpressionImpl
     implements RethrowExpression {
@@ -8388,8 +8549,8 @@
 /**
  * A return statement.
  *
- * > returnStatement ::=
- * >     'return' [Expression]? ';'
+ *    returnStatement ::=
+ *        'return' [Expression]? ';'
  */
 class ReturnStatementImpl extends StatementImpl implements ReturnStatement {
   /**
@@ -8447,8 +8608,8 @@
 /**
  * A script tag that can optionally occur at the beginning of a compilation unit.
  *
- * > scriptTag ::=
- * >     '#!' (~NEWLINE)* NEWLINE
+ *    scriptTag ::=
+ *        '#!' (~NEWLINE)* NEWLINE
  */
 class ScriptTagImpl extends AstNodeImpl implements ScriptTag {
   /**
@@ -8482,8 +8643,8 @@
 /**
  * A combinator that restricts the names being imported to those in a given list.
  *
- * > showCombinator ::=
- * >     'show' [SimpleIdentifier] (',' [SimpleIdentifier])*
+ *    showCombinator ::=
+ *        'show' [SimpleIdentifier] (',' [SimpleIdentifier])*
  */
 class ShowCombinatorImpl extends CombinatorImpl implements ShowCombinator {
   /**
@@ -8523,8 +8684,8 @@
 /**
  * A simple formal parameter.
  *
- * > simpleFormalParameter ::=
- * >     ('final' [TypeName] | 'var' | [TypeName])? [SimpleIdentifier]
+ *    simpleFormalParameter ::=
+ *        ('final' [TypeName] | 'var' | [TypeName])? [SimpleIdentifier]
  */
 class SimpleFormalParameterImpl extends NormalFormalParameterImpl
     implements SimpleFormalParameter {
@@ -8604,12 +8765,12 @@
 /**
  * A simple identifier.
  *
- * > simpleIdentifier ::=
- * >     initialCharacter internalCharacter*
- * >
- * > initialCharacter ::= '_' | '$' | letter
- * >
- * > internalCharacter ::= '_' | '$' | letter | digit
+ *    simpleIdentifier ::=
+ *        initialCharacter internalCharacter*
+ *
+ *    initialCharacter ::= '_' | '$' | letter
+ *
+ *    internalCharacter ::= '_' | '$' | letter | digit
  */
 class SimpleIdentifierImpl extends IdentifierImpl implements SimpleIdentifier {
   /**
@@ -8892,24 +9053,24 @@
 /**
  * A string literal expression that does not contain any interpolations.
  *
- * > simpleStringLiteral ::=
- * >     rawStringLiteral
- * >   | basicStringLiteral
- * >
- * > rawStringLiteral ::=
- * >     'r' basicStringLiteral
- * >
- * > simpleStringLiteral ::=
- * >     multiLineStringLiteral
- * >   | singleLineStringLiteral
- * >
- * > multiLineStringLiteral ::=
- * >     "'''" characters "'''"
- * >   | '"""' characters '"""'
- * >
- * > singleLineStringLiteral ::=
- * >     "'" characters "'"
- * >   | '"' characters '"'
+ *    simpleStringLiteral ::=
+ *        rawStringLiteral
+ *      | basicStringLiteral
+ *
+ *    rawStringLiteral ::=
+ *        'r' basicStringLiteral
+ *
+ *    simpleStringLiteral ::=
+ *        multiLineStringLiteral
+ *      | singleLineStringLiteral
+ *
+ *    multiLineStringLiteral ::=
+ *        "'''" characters "'''"
+ *      | '"""' characters '"""'
+ *
+ *    singleLineStringLiteral ::=
+ *        "'" characters "'"
+ *      | '"' characters '"'
  */
 class SimpleStringLiteralImpl extends SingleStringLiteralImpl
     implements SimpleStringLiteral {
@@ -8986,9 +9147,9 @@
 /**
  * A single string literal expression.
  *
- * > singleStringLiteral ::=
- * >     [SimpleStringLiteral]
- * >   | [StringInterpolation]
+ *    singleStringLiteral ::=
+ *        [SimpleStringLiteral]
+ *      | [StringInterpolation]
  */
 abstract class SingleStringLiteralImpl extends StringLiteralImpl
     implements SingleStringLiteral {}
@@ -8996,21 +9157,21 @@
 /**
  * A node that represents a statement.
  *
- * > statement ::=
- * >     [Block]
- * >   | [VariableDeclarationStatement]
- * >   | [ForStatement]
- * >   | [ForEachStatement]
- * >   | [WhileStatement]
- * >   | [DoStatement]
- * >   | [SwitchStatement]
- * >   | [IfStatement]
- * >   | [TryStatement]
- * >   | [BreakStatement]
- * >   | [ContinueStatement]
- * >   | [ReturnStatement]
- * >   | [ExpressionStatement]
- * >   | [FunctionDeclarationStatement]
+ *    statement ::=
+ *        [Block]
+ *      | [VariableDeclarationStatement]
+ *      | [ForStatement]
+ *      | [ForEachStatement]
+ *      | [WhileStatement]
+ *      | [DoStatement]
+ *      | [SwitchStatement]
+ *      | [IfStatement]
+ *      | [TryStatement]
+ *      | [BreakStatement]
+ *      | [ContinueStatement]
+ *      | [ReturnStatement]
+ *      | [ExpressionStatement]
+ *      | [FunctionDeclarationStatement]
  */
 abstract class StatementImpl extends AstNodeImpl implements Statement {
   @override
@@ -9020,9 +9181,9 @@
 /**
  * A string interpolation literal.
  *
- * > stringInterpolation ::=
- * >     ''' [InterpolationElement]* '''
- * >   | '"' [InterpolationElement]* '"'
+ *    stringInterpolation ::=
+ *        ''' [InterpolationElement]* '''
+ *      | '"' [InterpolationElement]* '"'
  */
 class StringInterpolationImpl extends SingleStringLiteralImpl
     implements StringInterpolation {
@@ -9191,10 +9352,10 @@
 /**
  * A string literal expression.
  *
- * > stringLiteral ::=
- * >     [SimpleStringLiteral]
- * >   | [AdjacentStrings]
- * >   | [StringInterpolation]
+ *    stringLiteral ::=
+ *        [SimpleStringLiteral]
+ *      | [AdjacentStrings]
+ *      | [StringInterpolation]
  */
 abstract class StringLiteralImpl extends LiteralImpl implements StringLiteral {
   @override
@@ -9220,8 +9381,8 @@
  * The invocation of a superclass' constructor from within a constructor's
  * initialization list.
  *
- * > superInvocation ::=
- * >     'super' ('.' [SimpleIdentifier])? [ArgumentList]
+ *    superInvocation ::=
+ *        'super' ('.' [SimpleIdentifier])? [ArgumentList]
  */
 class SuperConstructorInvocationImpl extends ConstructorInitializerImpl
     implements SuperConstructorInvocation {
@@ -9308,8 +9469,8 @@
 /**
  * A super expression.
  *
- * > superExpression ::=
- * >     'super'
+ *    superExpression ::=
+ *        'super'
  */
 class SuperExpressionImpl extends ExpressionImpl implements SuperExpression {
   /**
@@ -9346,8 +9507,8 @@
 /**
  * A case in a switch statement.
  *
- * > switchCase ::=
- * >     [SimpleIdentifier]* 'case' [Expression] ':' [Statement]*
+ *    switchCase ::=
+ *        [SimpleIdentifier]* 'case' [Expression] ':' [Statement]*
  */
 class SwitchCaseImpl extends SwitchMemberImpl implements SwitchCase {
   /**
@@ -9395,8 +9556,8 @@
 /**
  * The default case in a switch statement.
  *
- * > switchDefault ::=
- * >     [SimpleIdentifier]* 'default' ':' [Statement]*
+ *    switchDefault ::=
+ *        [SimpleIdentifier]* 'default' ':' [Statement]*
  */
 class SwitchDefaultImpl extends SwitchMemberImpl implements SwitchDefault {
   /**
@@ -9427,9 +9588,9 @@
 /**
  * An element within a switch statement.
  *
- * > switchMember ::=
- * >     switchCase
- * >   | switchDefault
+ *    switchMember ::=
+ *        switchCase
+ *      | switchDefault
  */
 abstract class SwitchMemberImpl extends AstNodeImpl implements SwitchMember {
   /**
@@ -9488,8 +9649,8 @@
 /**
  * A switch statement.
  *
- * > switchStatement ::=
- * >     'switch' '(' [Expression] ')' '{' [SwitchCase]* [SwitchDefault]? '}'
+ *    switchStatement ::=
+ *        'switch' '(' [Expression] ')' '{' [SwitchCase]* [SwitchDefault]? '}'
  */
 class SwitchStatementImpl extends StatementImpl implements SwitchStatement {
   /**
@@ -9584,8 +9745,8 @@
 /**
  * A symbol literal expression.
  *
- * > symbolLiteral ::=
- * >     '#' (operator | (identifier ('.' identifier)*))
+ *    symbolLiteral ::=
+ *        '#' (operator | (identifier ('.' identifier)*))
  */
 class SymbolLiteralImpl extends LiteralImpl implements SymbolLiteral {
   /**
@@ -9627,8 +9788,8 @@
 /**
  * A this expression.
  *
- * > thisExpression ::=
- * >     'this'
+ *    thisExpression ::=
+ *        'this'
  */
 class ThisExpressionImpl extends ExpressionImpl implements ThisExpression {
   /**
@@ -9665,8 +9826,8 @@
 /**
  * A throw expression.
  *
- * > throwExpression ::=
- * >     'throw' [Expression]
+ *    throwExpression ::=
+ *        'throw' [Expression]
  */
 class ThrowExpressionImpl extends ExpressionImpl implements ThrowExpression {
   /**
@@ -9724,9 +9885,9 @@
 /**
  * The declaration of one or more top-level variables of the same type.
  *
- * > topLevelVariableDeclaration ::=
- * >     ('final' | 'const') type? staticFinalDeclarationList ';'
- * >   | variableDeclaration ';'
+ *    topLevelVariableDeclaration ::=
+ *        ('final' | 'const') type? staticFinalDeclarationList ';'
+ *      | variableDeclaration ';'
  */
 class TopLevelVariableDeclarationImpl extends CompilationUnitMemberImpl
     implements TopLevelVariableDeclaration {
@@ -9785,11 +9946,11 @@
 /**
  * A try statement.
  *
- * > tryStatement ::=
- * >     'try' [Block] ([CatchClause]+ finallyClause? | finallyClause)
- * >
- * > finallyClause ::=
- * >     'finally' [Block]
+ *    tryStatement ::=
+ *        'try' [Block] ([CatchClause]+ finallyClause? | finallyClause)
+ *
+ *    finallyClause ::=
+ *        'finally' [Block]
  */
 class TryStatementImpl extends StatementImpl implements TryStatement {
   /**
@@ -9887,12 +10048,12 @@
 /**
  * The declaration of a type alias.
  *
- * > typeAlias ::=
- * >     'typedef' typeAliasBody
- * >
- * > typeAliasBody ::=
- * >     classTypeAlias
- * >   | functionTypeAlias
+ *    typeAlias ::=
+ *        'typedef' typeAliasBody
+ *
+ *    typeAliasBody ::=
+ *        classTypeAlias
+ *      | functionTypeAlias
  */
 abstract class TypeAliasImpl extends NamedCompilationUnitMemberImpl
     implements TypeAlias {
@@ -9925,8 +10086,8 @@
 /**
  * A list of type arguments.
  *
- * > typeArguments ::=
- * >     '<' typeName (',' typeName)* '>'
+ *    typeArguments ::=
+ *        '<' typeName (',' typeName)* '>'
  */
 class TypeArgumentListImpl extends AstNodeImpl implements TypeArgumentList {
   /**
@@ -9980,9 +10141,9 @@
 /**
  * A literal that has a type associated with it.
  *
- * > typedLiteral ::=
- * >     [ListLiteral]
- * >   | [MapLiteral]
+ *    typedLiteral ::=
+ *        [ListLiteral]
+ *      | [MapLiteral]
  */
 abstract class TypedLiteralImpl extends LiteralImpl implements TypedLiteral {
   /**
@@ -10026,8 +10187,8 @@
 /**
  * The name of a type, which can optionally include type arguments.
  *
- * > typeName ::=
- * >     [Identifier] typeArguments?
+ *    typeName ::=
+ *        [Identifier] typeArguments?
  */
 class TypeNameImpl extends AstNodeImpl implements TypeName {
   /**
@@ -10111,8 +10272,8 @@
 /**
  * A type parameter.
  *
- * > typeParameter ::=
- * >     [SimpleIdentifier] ('extends' [TypeName])?
+ *    typeParameter ::=
+ *        [SimpleIdentifier] ('extends' [TypeName])?
  */
 class TypeParameterImpl extends DeclarationImpl implements TypeParameter {
   /**
@@ -10194,8 +10355,8 @@
 /**
  * Type parameters within a declaration.
  *
- * > typeParameterList ::=
- * >     '<' [TypeParameter] (',' [TypeParameter])* '>'
+ *    typeParameterList ::=
+ *        '<' [TypeParameter] (',' [TypeParameter])* '>'
  */
 class TypeParameterListImpl extends AstNodeImpl implements TypeParameterList {
   /**
@@ -10248,10 +10409,10 @@
 /**
  * A directive that references a URI.
  *
- * > uriBasedDirective ::=
- * >     [ExportDirective]
- * >   | [ImportDirective]
- * >   | [PartDirective]
+ *    uriBasedDirective ::=
+ *        [ExportDirective]
+ *      | [ImportDirective]
+ *      | [PartDirective]
  */
 abstract class UriBasedDirectiveImpl extends DirectiveImpl
     implements UriBasedDirective {
@@ -10354,8 +10515,8 @@
  * An identifier that has an initial value associated with it. Instances of this
  * class are always children of the class [VariableDeclarationList].
  *
- * > variableDeclaration ::=
- * >     [SimpleIdentifier] ('=' [Expression])?
+ *    variableDeclaration ::=
+ *        [SimpleIdentifier] ('=' [Expression])?
  *
  * TODO(paulberry): the grammar does not allow metadata to be associated with
  * a VariableDeclaration, and currently we don't record comments for it either.
@@ -10472,14 +10633,14 @@
 /**
  * The declaration of one or more variables of the same type.
  *
- * > variableDeclarationList ::=
- * >     finalConstVarOrType [VariableDeclaration] (',' [VariableDeclaration])*
- * >
- * > finalConstVarOrType ::=
- * >   | 'final' [TypeName]?
- * >   | 'const' [TypeName]?
- * >   | 'var'
- * >   | [TypeName]
+ *    variableDeclarationList ::=
+ *        finalConstVarOrType [VariableDeclaration] (',' [VariableDeclaration])*
+ *
+ *    finalConstVarOrType ::=
+ *      | 'final' [TypeName]?
+ *      | 'const' [TypeName]?
+ *      | 'var'
+ *      | [TypeName]
  */
 class VariableDeclarationListImpl extends AnnotatedNodeImpl
     implements VariableDeclarationList {
@@ -10568,8 +10729,8 @@
  * A list of variables that are being declared in a context where a statement is
  * required.
  *
- * > variableDeclarationStatement ::=
- * >     [VariableDeclarationList] ';'
+ *    variableDeclarationStatement ::=
+ *        [VariableDeclarationList] ';'
  */
 class VariableDeclarationStatementImpl extends StatementImpl
     implements VariableDeclarationStatement {
@@ -10621,8 +10782,8 @@
 /**
  * A while statement.
  *
- * > whileStatement ::=
- * >     'while' '(' [Expression] ')' [Statement]
+ *    whileStatement ::=
+ *        'while' '(' [Expression] ')' [Statement]
  */
 class WhileStatementImpl extends StatementImpl implements WhileStatement {
   /**
@@ -10702,8 +10863,8 @@
 /**
  * The with clause in a class declaration.
  *
- * > withClause ::=
- * >     'with' [TypeName] (',' [TypeName])*
+ *    withClause ::=
+ *        'with' [TypeName] (',' [TypeName])*
  */
 class WithClauseImpl extends AstNodeImpl implements WithClause {
   /**
@@ -10750,8 +10911,8 @@
 /**
  * A yield statement.
  *
- * > yieldStatement ::=
- * >     'yield' '*'? [Expression] ‘;’
+ *    yieldStatement ::=
+ *        'yield' '*'? [Expression] ‘;’
  */
 class YieldStatementImpl extends StatementImpl implements YieldStatement {
   /**
diff --git a/pkg/analyzer/lib/src/dart/ast/token.dart b/pkg/analyzer/lib/src/dart/ast/token.dart
index 02d28e5..1791990 100644
--- a/pkg/analyzer/lib/src/dart/ast/token.dart
+++ b/pkg/analyzer/lib/src/dart/ast/token.dart
@@ -39,6 +39,7 @@
   /**
    * The first comment in the list of comments that precede this token.
    */
+  @override
   CommentToken _precedingComment;
 
   /**
@@ -54,6 +55,7 @@
   @override
   CommentToken get precedingComments => _precedingComment;
 
+  @override
   void set precedingComments(CommentToken comment) {
     _precedingComment = comment;
     _setCommentParent(_precedingComment);
@@ -168,6 +170,7 @@
   /**
    * The first comment in the list of comments that precede this token.
    */
+  @override
   CommentToken _precedingComment;
 
   /**
diff --git a/pkg/analyzer/lib/src/dart/element/builder.dart b/pkg/analyzer/lib/src/dart/element/builder.dart
index 82d3761..23869ee 100644
--- a/pkg/analyzer/lib/src/dart/element/builder.dart
+++ b/pkg/analyzer/lib/src/dart/element/builder.dart
@@ -160,6 +160,8 @@
 
   @override
   Object visitExportDirective(ExportDirective node) {
+    // Remove previous element. (It will remain null if the target is missing.)
+    node.element = null;
     Source exportedSource = node.source;
     if (exportedSource != null && context.exists(exportedSource)) {
       // The exported source will be null if the URI in the export
@@ -180,10 +182,16 @@
         node.element = exportElement;
         exports.add(exportElement);
         if (exportSourceKindMap[exportedSource] != SourceKind.LIBRARY) {
+          int offset = node.offset;
+          int length = node.length;
+          if (uriLiteral != null) {
+            offset = uriLiteral.offset;
+            length = uriLiteral.length;
+          }
           errors.add(new AnalysisError(
-              exportedSource,
-              uriLiteral.offset,
-              uriLiteral.length,
+              libraryElement.source,
+              offset,
+              length,
               CompileTimeErrorCode.EXPORT_OF_NON_LIBRARY,
               [uriLiteral.toSource()]));
         }
@@ -194,6 +202,9 @@
 
   @override
   Object visitImportDirective(ImportDirective node) {
+    // Remove previous element. (It will remain null if the target is missing.)
+    node.element = null;
+
     String uriContent = node.uriContent;
     if (DartUriResolver.isDartExtUri(uriContent)) {
       libraryElement.hasExtUri = true;
@@ -234,11 +245,17 @@
         node.element = importElement;
         imports.add(importElement);
         if (importSourceKindMap[importedSource] != SourceKind.LIBRARY) {
+          int offset = node.offset;
+          int length = node.length;
+          if (uriLiteral != null) {
+            offset = uriLiteral.offset;
+            length = uriLiteral.length;
+          }
           ErrorCode errorCode = (importElement.isDeferred
               ? StaticWarningCode.IMPORT_OF_NON_LIBRARY
               : CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY);
-          errors.add(new AnalysisError(importedSource, uriLiteral.offset,
-              uriLiteral.length, errorCode, [uriLiteral.toSource()]));
+          errors.add(new AnalysisError(libraryElement.source, offset, length,
+              errorCode, [uriLiteral.toSource()]));
         }
       }
     }
@@ -365,6 +382,7 @@
       if (stackTraceParameter != null) {
         LocalVariableElementImpl stackTrace =
             new LocalVariableElementImpl.forNode(stackTraceParameter);
+        _setCodeRange(stackTrace, stackTraceParameter);
         _currentHolder.addLocalVariable(stackTrace);
         stackTraceParameter.staticElement = stackTrace;
       }
@@ -396,6 +414,7 @@
     }
     SimpleIdentifier className = node.name;
     ClassElementImpl element = new ClassElementImpl.forNode(className);
+    _setCodeRange(element, node);
     element.metadata = _createElementAnnotations(node.metadata);
     List<TypeParameterElement> typeParameters = holder.typeParameters;
     List<DartType> typeArguments = _createTypeParameterTypes(typeParameters);
@@ -445,6 +464,7 @@
     _visitChildren(holder, node);
     SimpleIdentifier className = node.name;
     ClassElementImpl element = new ClassElementImpl.forNode(className);
+    _setCodeRange(element, node);
     element.metadata = _createElementAnnotations(node.metadata);
     element.abstract = node.abstractKeyword != null;
     element.mixinApplication = true;
@@ -462,6 +482,14 @@
   }
 
   @override
+  Object visitCompilationUnit(CompilationUnit node) {
+    if (compilationUnitElement is ElementImpl) {
+      _setCodeRange(compilationUnitElement as ElementImpl, node);
+    }
+    return super.visitCompilationUnit(node);
+  }
+
+  @override
   Object visitConstructorDeclaration(ConstructorDeclaration node) {
     ElementHolder holder = new ElementHolder();
     bool wasInFunction = _inFunction;
@@ -475,6 +503,7 @@
     SimpleIdentifier constructorName = node.name;
     ConstructorElementImpl element =
         new ConstructorElementImpl.forNode(constructorName);
+    _setCodeRange(element, node);
     element.metadata = _createElementAnnotations(node.metadata);
     setElementDocumentationComment(element, node);
     if (node.externalKeyword != null) {
@@ -516,6 +545,7 @@
     SimpleIdentifier variableName = node.identifier;
     LocalVariableElementImpl element =
         new LocalVariableElementImpl.forNode(variableName);
+    _setCodeRange(element, node);
     element.metadata = _createElementAnnotations(node.metadata);
     ForEachStatement statement = node.parent as ForEachStatement;
     int declarationEnd = node.offset + node.length;
@@ -548,6 +578,7 @@
     } else {
       parameter = new DefaultParameterElementImpl.forNode(parameterName);
     }
+    _setCodeRange(parameter, node);
     parameter.const3 = node.isConst;
     parameter.final2 = node.isFinal;
     parameter.parameterKind = node.kind;
@@ -584,6 +615,7 @@
   Object visitEnumDeclaration(EnumDeclaration node) {
     SimpleIdentifier enumName = node.name;
     ClassElementImpl enumElement = new ClassElementImpl.forNode(enumName);
+    _setCodeRange(enumElement, node);
     enumElement.metadata = _createElementAnnotations(node.metadata);
     enumElement.enum2 = true;
     setElementDocumentationComment(enumElement, node);
@@ -613,6 +645,7 @@
           _fieldMap == null ? null : _fieldMap[parameterName.name];
       FieldFormalParameterElementImpl parameter =
           new FieldFormalParameterElementImpl.forNode(parameterName);
+      _setCodeRange(parameter, node);
       parameter.const3 = node.isConst;
       parameter.final2 = node.isFinal;
       parameter.parameterKind = node.kind;
@@ -654,6 +687,7 @@
         SimpleIdentifier functionName = node.name;
         FunctionElementImpl element =
             new FunctionElementImpl.forNode(functionName);
+        _setCodeRange(element, node);
         element.metadata = _createElementAnnotations(node.metadata);
         setElementDocumentationComment(element, node);
         if (node.externalKeyword != null) {
@@ -701,6 +735,7 @@
         if (node.isGetter) {
           PropertyAccessorElementImpl getter =
               new PropertyAccessorElementImpl.forNode(propertyNameNode);
+          _setCodeRange(getter, node);
           getter.metadata = _createElementAnnotations(node.metadata);
           setElementDocumentationComment(getter, node);
           if (node.externalKeyword != null) {
@@ -728,6 +763,7 @@
         } else {
           PropertyAccessorElementImpl setter =
               new PropertyAccessorElementImpl.forNode(propertyNameNode);
+          _setCodeRange(setter, node);
           setter.metadata = _createElementAnnotations(node.metadata);
           setElementDocumentationComment(setter, node);
           if (node.externalKeyword != null) {
@@ -779,6 +815,7 @@
     FunctionBody body = node.body;
     FunctionElementImpl element =
         new FunctionElementImpl.forOffset(node.beginToken.offset);
+    _setCodeRange(element, node);
     element.functions = holder.functions;
     element.labels = holder.labels;
     element.localVariables = holder.localVariables;
@@ -817,6 +854,7 @@
     List<TypeParameterElement> typeParameters = holder.typeParameters;
     FunctionTypeAliasElementImpl element =
         new FunctionTypeAliasElementImpl.forNode(aliasName);
+    _setCodeRange(element, node);
     element.metadata = _createElementAnnotations(node.metadata);
     setElementDocumentationComment(element, node);
     element.parameters = parameters;
@@ -835,6 +873,7 @@
       SimpleIdentifier parameterName = node.identifier;
       ParameterElementImpl parameter =
           new ParameterElementImpl.forNode(parameterName);
+      _setCodeRange(parameter, node);
       parameter.parameterKind = node.kind;
       _setParameterVisibleRange(node, parameter);
       _currentHolder.addParameter(parameter);
@@ -867,6 +906,7 @@
       SimpleIdentifier labelName = label.label;
       LabelElementImpl element =
           new LabelElementImpl.forNode(labelName, onSwitchStatement, false);
+      _setCodeRange(element, node);
       _currentHolder.addLabel(element);
       labelName.staticElement = element;
     }
@@ -902,6 +942,7 @@
         }
         MethodElementImpl element =
             new MethodElementImpl(nameOfMethod, methodName.offset);
+        _setCodeRange(element, node);
         element.metadata = _createElementAnnotations(node.metadata);
         setElementDocumentationComment(element, node);
         element.abstract = node.isAbstract;
@@ -940,6 +981,7 @@
         if (node.isGetter) {
           PropertyAccessorElementImpl getter =
               new PropertyAccessorElementImpl.forNode(propertyNameNode);
+          _setCodeRange(getter, node);
           getter.metadata = _createElementAnnotations(node.metadata);
           setElementDocumentationComment(getter, node);
           if (node.externalKeyword != null) {
@@ -967,6 +1009,7 @@
         } else {
           PropertyAccessorElementImpl setter =
               new PropertyAccessorElementImpl.forNode(propertyNameNode);
+          _setCodeRange(setter, node);
           setter.metadata = _createElementAnnotations(node.metadata);
           setElementDocumentationComment(setter, node);
           if (node.externalKeyword != null) {
@@ -1045,6 +1088,7 @@
       SimpleIdentifier parameterName = node.identifier;
       ParameterElementImpl parameter =
           new ParameterElementImpl.forNode(parameterName);
+      _setCodeRange(parameter, node);
       parameter.const3 = node.isConst;
       parameter.final2 = node.isFinal;
       parameter.parameterKind = node.kind;
@@ -1065,7 +1109,8 @@
   Object visitSwitchCase(SwitchCase node) {
     for (Label label in node.labels) {
       SimpleIdentifier labelName = label.label;
-      LabelElementImpl element = new LabelElementImpl.forNode(labelName, false, true);
+      LabelElementImpl element =
+          new LabelElementImpl.forNode(labelName, false, true);
       _currentHolder.addLabel(element);
       labelName.staticElement = element;
     }
@@ -1076,7 +1121,8 @@
   Object visitSwitchDefault(SwitchDefault node) {
     for (Label label in node.labels) {
       SimpleIdentifier labelName = label.label;
-      LabelElementImpl element = new LabelElementImpl.forNode(labelName, false, true);
+      LabelElementImpl element =
+          new LabelElementImpl.forNode(labelName, false, true);
       _currentHolder.addLabel(element);
       labelName.staticElement = element;
     }
@@ -1088,6 +1134,7 @@
     SimpleIdentifier parameterName = node.name;
     TypeParameterElementImpl typeParameter =
         new TypeParameterElementImpl.forNode(parameterName);
+    _setCodeRange(typeParameter, node);
     typeParameter.metadata = _createElementAnnotations(node.metadata);
     TypeParameterTypeImpl typeParameterType =
         new TypeParameterTypeImpl(typeParameter);
@@ -1116,6 +1163,7 @@
       }
       element = field;
       field.static = fieldNode.isStatic;
+      _setCodeRange(element, node);
       setElementDocumentationComment(element, fieldNode);
       field.hasImplicitType = varList.type == null;
       _currentHolder.addField(field);
@@ -1129,6 +1177,7 @@
         variable = new LocalVariableElementImpl.forNode(variableName);
       }
       element = variable;
+      _setCodeRange(element, node);
       Block enclosingBlock = node.getAncestor((node) => node is Block);
       // TODO(brianwilkerson) This isn't right for variables declared in a for
       // loop.
@@ -1145,6 +1194,7 @@
         variable = new TopLevelVariableElementImpl.forNode(variableName);
       }
       element = variable;
+      _setCodeRange(element, node);
       if (varList.parent is TopLevelVariableDeclaration) {
         setElementDocumentationComment(element, varList.parent);
       }
@@ -1207,8 +1257,9 @@
       elementAnnotations = _createElementAnnotations(node.metadata);
     }
     for (VariableDeclaration variableDeclaration in node.variables) {
-      (variableDeclaration.element as ElementImpl).metadata =
-          elementAnnotations;
+      ElementImpl element = variableDeclaration.element as ElementImpl;
+      _setCodeRange(element, node.parent);
+      element.metadata = elementAnnotations;
     }
     return null;
   }
@@ -1300,6 +1351,10 @@
     return null;
   }
 
+  void _setCodeRange(ElementImpl element, AstNode node) {
+    element.setCodeRange(node.offset, node.length);
+  }
+
   /**
    * Sets the visible source range for formal parameter.
    */
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 5305395..e3f4dfe 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -16,6 +16,7 @@
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/generated/constant.dart'
     show DartObject, EvaluationResultImpl;
+import 'package:analyzer/src/generated/element_handle.dart';
 import 'package:analyzer/src/generated/engine.dart'
     show AnalysisContext, AnalysisEngine;
 import 'package:analyzer/src/generated/java_core.dart';
@@ -85,11 +86,13 @@
    * A list containing all of the mixins that are applied to the class being
    * extended in order to derive the superclass of this class.
    */
+  @override
   List<InterfaceType> mixins = InterfaceType.EMPTY_LIST;
 
   /**
    * A list containing all of the interfaces that are implemented by this class.
    */
+  @override
   List<InterfaceType> interfaces = InterfaceType.EMPTY_LIST;
 
   /**
@@ -101,11 +104,13 @@
    * The superclass of the class, or `null` if the class does not have an
    * explicit superclass.
    */
+  @override
   InterfaceType supertype;
 
   /**
    * The type defined by the class.
    */
+  @override
   InterfaceType type;
 
   /**
@@ -910,6 +915,7 @@
   /**
    * The source that corresponds to this compilation unit.
    */
+  @override
   Source source;
 
   /**
@@ -1562,12 +1568,23 @@
   static String _DEPRECATED_VARIABLE_NAME = "deprecated";
 
   /**
+   * The name of `meta` library, used to define analysis annotations.
+   */
+  static String _META_LIB_NAME = "meta";
+
+  /**
    * The name of the top-level variable used to mark a method as being expected
    * to override an inherited method.
    */
   static String _OVERRIDE_VARIABLE_NAME = "override";
 
   /**
+   * The name of the top-level variable used to mark a method as being
+   * protected.
+   */
+  static String _PROTECTED_VARIABLE_NAME = "protected";
+
+  /**
    * The name of the top-level variable used to mark a class as implementing a
    * proxy object.
    */
@@ -1580,7 +1597,7 @@
   Element element;
 
   /**
-   * The compliation unit in which this annotation appears.
+   * The compilation unit in which this annotation appears.
    */
   final CompilationUnitElementImpl compilationUnit;
 
@@ -1611,51 +1628,33 @@
 
   @override
   bool get isDeprecated {
-    if (element != null) {
-      LibraryElement library = element.library;
-      if (library != null && library.isDartCore) {
-        if (element is ConstructorElement) {
-          ConstructorElement constructorElement = element as ConstructorElement;
-          if (constructorElement.enclosingElement.name ==
-              _DEPRECATED_CLASS_NAME) {
-            return true;
-          }
-        } else if (element is PropertyAccessorElement &&
-            element.name == _DEPRECATED_VARIABLE_NAME) {
-          return true;
-        }
+    if (element?.library?.isDartCore == true) {
+      if (element is ConstructorElement) {
+        return element.enclosingElement.name == _DEPRECATED_CLASS_NAME;
+      } else if (element is PropertyAccessorElement) {
+        return element.name == _DEPRECATED_VARIABLE_NAME;
       }
     }
     return false;
   }
 
   @override
-  bool get isOverride {
-    if (element != null) {
-      LibraryElement library = element.library;
-      if (library != null && library.isDartCore) {
-        if (element is PropertyAccessorElement &&
-            element.name == _OVERRIDE_VARIABLE_NAME) {
-          return true;
-        }
-      }
-    }
-    return false;
-  }
+  bool get isOverride =>
+      element is PropertyAccessorElement &&
+      element.name == _OVERRIDE_VARIABLE_NAME &&
+      element.library?.isDartCore == true;
 
   @override
-  bool get isProxy {
-    if (element != null) {
-      LibraryElement library = element.library;
-      if (library != null && library.isDartCore) {
-        if (element is PropertyAccessorElement &&
-            element.name == PROXY_VARIABLE_NAME) {
-          return true;
-        }
-      }
-    }
-    return false;
-  }
+  bool get isProtected =>
+      element is PropertyAccessorElement &&
+      element.name == _PROTECTED_VARIABLE_NAME &&
+      element.library?.name == _META_LIB_NAME;
+
+  @override
+  bool get isProxy =>
+      element is PropertyAccessorElement &&
+      element.name == PROXY_VARIABLE_NAME &&
+      element.library?.isDartCore == true;
 
   /**
    * Get the library containing this annotation.
@@ -1736,6 +1735,17 @@
   int _docRangeLength;
 
   /**
+   * The offset of the beginning of the element's code in the file that contains
+   * the element, or `null` if the element is synthetic.
+   */
+  int _codeOffset;
+
+  /**
+   * The length of the element's code, or `null` if the element is synthetic.
+   */
+  int _codeLength;
+
+  /**
    * Initialize a newly created element to have the given [name] at the given
    * [_nameOffset].
    */
@@ -1749,6 +1759,17 @@
   ElementImpl.forNode(Identifier name)
       : this(name == null ? "" : name.name, name == null ? -1 : name.offset);
 
+  /**
+   * The length of the element's code, or `null` if the element is synthetic.
+   */
+  int get codeLength => _codeLength;
+
+  /**
+   * The offset of the beginning of the element's code in the file that contains
+   * the element, or `null` if the element is synthetic.
+   */
+  int get codeOffset => _codeOffset;
+
   @override
   AnalysisContext get context {
     if (_enclosingElement == null) {
@@ -1837,6 +1858,16 @@
   }
 
   @override
+  bool get isProtected {
+    for (ElementAnnotation annotation in metadata) {
+      if (annotation.isProtected) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  @override
   bool get isPublic => !isPrivate;
 
   @override
@@ -2019,6 +2050,14 @@
   }
 
   /**
+   * Set the code range for this element.
+   */
+  void setCodeRange(int offset, int length) {
+    _codeOffset = offset;
+    _codeLength = length;
+  }
+
+  /**
    * Set the documentation comment source range for this element.
    */
   void setDocRange(int offset, int length) {
@@ -3098,6 +3137,24 @@
         nameLength = name != null ? name.length : 0;
 
   @override
+  int get codeLength {
+    if (_definingCompilationUnit is CompilationUnitElementImpl) {
+      return (_definingCompilationUnit as CompilationUnitElementImpl)
+          .codeLength;
+    }
+    return null;
+  }
+
+  @override
+  int get codeOffset {
+    if (_definingCompilationUnit is CompilationUnitElementImpl) {
+      return (_definingCompilationUnit as CompilationUnitElementImpl)
+          .codeOffset;
+    }
+    return null;
+  }
+
+  @override
   CompilationUnitElement get definingCompilationUnit =>
       _definingCompilationUnit;
 
@@ -3148,9 +3205,6 @@
   }
 
   @override
-  int get hashCode => _definingCompilationUnit.hashCode;
-
-  @override
   bool get hasLoadLibraryFunction {
     if (_definingCompilationUnit.hasLoadLibraryFunction) {
       return true;
@@ -3244,6 +3298,7 @@
   @override
   LibraryElement get library => this;
 
+  @override
   List<LibraryElement> get libraryCycle {
     if (_libraryCycle != null) {
       return _libraryCycle;
@@ -3265,6 +3320,17 @@
       indices[library] = index;
       active.add(library);
       stack.add(library);
+      LibraryElementImpl getActualLibrary(LibraryElement lib) {
+        // TODO(paulberry): this means that computing a library cycle will be
+        // expensive for libraries resynthesized from summaries, since it will
+        // require fully resynthesizing all the libraries in the cycle as well
+        // as any libraries they import or export.  Try to find a better way.
+        if (lib is LibraryElementHandle) {
+          return lib.actualElement;
+        } else {
+          return lib;
+        }
+      }
       void recurse(LibraryElementImpl child) {
         if (!indices.containsKey(child)) {
           // We haven't visited this child yet, so recurse on the child,
@@ -3282,9 +3348,11 @@
       // Recurse on all of the children in the import/export graph, filtering
       // out those for which library cycles have already been computed.
       library.exportedLibraries
+          .map(getActualLibrary)
           .where((l) => l._libraryCycle == null)
           .forEach(recurse);
       library.importedLibraries
+          .map(getActualLibrary)
           .where((l) => l._libraryCycle == null)
           .forEach(recurse);
 
@@ -3365,11 +3433,6 @@
   }
 
   @override
-  bool operator ==(Object object) =>
-      object is LibraryElementImpl &&
-      _definingCompilationUnit == object.definingCompilationUnit;
-
-  @override
   accept(ElementVisitor visitor) => visitor.visitLibraryElement(this);
 
   /**
@@ -3929,6 +3992,9 @@
   }
 
   @override
+  bool get isProtected => false;
+
+  @override
   bool get isPublic => !isPrivate;
 
   @override
diff --git a/pkg/analyzer/lib/src/dart/element/member.dart b/pkg/analyzer/lib/src/dart/element/member.dart
index 558b5ec..28bce1e 100644
--- a/pkg/analyzer/lib/src/dart/element/member.dart
+++ b/pkg/analyzer/lib/src/dart/element/member.dart
@@ -455,6 +455,7 @@
   @override
   String get documentationComment => _baseElement.documentationComment;
 
+  @override
   int get id => _baseElement.id;
 
   @override
@@ -467,6 +468,9 @@
   bool get isPrivate => _baseElement.isPrivate;
 
   @override
+  bool get isProtected => _baseElement.isProtected;
+
+  @override
   bool get isPublic => _baseElement.isPublic;
 
   @override
diff --git a/pkg/analyzer/lib/src/dart/element/type.dart b/pkg/analyzer/lib/src/dart/element/type.dart
index cfc076ff..29658fb 100644
--- a/pkg/analyzer/lib/src/dart/element/type.dart
+++ b/pkg/analyzer/lib/src/dart/element/type.dart
@@ -1285,13 +1285,13 @@
     // In other words, given the set of all types R such that T << Future<R>,
     // let S be the most specific of those types, if any such S exists.
     //
-    // Since we only care about the most specific type, it is sufficent to
+    // Since we only care about the most specific type, it is sufficient to
     // look at the types appearing as a parameter to Future in the type
     // hierarchy of T.  We don't need to consider the supertypes of those
     // types, since they are by definition less specific.
     List<DartType> candidateTypes =
         _searchTypeHierarchyForFutureTypeParameters();
-    DartType flattenResult = _findMostSpecificType(candidateTypes, typeSystem);
+    DartType flattenResult = findMostSpecificType(candidateTypes, typeSystem);
     if (flattenResult != null) {
       return flattenResult;
     }
@@ -1923,7 +1923,7 @@
    * If there is a single type which is at least as specific as all of the
    * types in [types], return it.  Otherwise return `null`.
    */
-  static DartType _findMostSpecificType(
+  static DartType findMostSpecificType(
       List<DartType> types, TypeSystem typeSystem) {
     // The << relation ("more specific than") is a partial ordering on types,
     // so to find the most specific type of a set, we keep a bucket of the most
diff --git a/pkg/analyzer/lib/src/error.dart b/pkg/analyzer/lib/src/error.dart
index 35ffb7c..166ba13 100644
--- a/pkg/analyzer/lib/src/error.dart
+++ b/pkg/analyzer/lib/src/error.dart
@@ -20,6 +20,7 @@
 
   String get message => toString();
 
+  @override
   String toString() {
     var builder = new StringBuffer();
 
@@ -89,5 +90,6 @@
       new UnmodifiableListView<AnalyzerError>(_errors);
 
   String get message => toString();
+  @override
   String toString() => errors.join("\n");
 }
diff --git a/pkg/analyzer/lib/src/generated/constant.dart b/pkg/analyzer/lib/src/generated/constant.dart
index b2d1e0d..8d4de8e 100644
--- a/pkg/analyzer/lib/src/generated/constant.dart
+++ b/pkg/analyzer/lib/src/generated/constant.dart
@@ -2505,6 +2505,7 @@
   /**
    * The run-time type of this object.
    */
+  @override
   final ParameterizedType type;
 
   /**
diff --git a/pkg/analyzer/lib/src/generated/element_handle.dart b/pkg/analyzer/lib/src/generated/element_handle.dart
index 84b4bdc..9ed587f 100644
--- a/pkg/analyzer/lib/src/generated/element_handle.dart
+++ b/pkg/analyzer/lib/src/generated/element_handle.dart
@@ -4,10 +4,10 @@
 
 library analyzer.src.generated.element_handle;
 
+import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/src/generated/constant.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/java_engine.dart';
@@ -358,6 +358,9 @@
   bool get isPrivate => actualElement.isPrivate;
 
   @override
+  bool get isProtected => actualElement.isProtected;
+
+  @override
   bool get isPublic => actualElement.isPublic;
 
   @override
@@ -766,6 +769,9 @@
   ElementKind get kind => ElementKind.LIBRARY;
 
   @override
+  List<LibraryElement> get libraryCycle => actualElement.libraryCycle;
+
+  @override
   FunctionElement get loadLibraryFunction => actualElement.loadLibraryFunction;
 
   @override
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index c3c343b..a9a3881 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -2539,6 +2539,7 @@
   /**
    * The name of the synthetic identifier.
    */
+  @override
   final String name;
 
   /**
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index c3aa019..57d35d9 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -922,6 +922,7 @@
    * The analysis errors associated with a source, or `null` if there are no
    * errors.
    */
+  @override
   final List<AnalysisError> errors;
 
   /**
@@ -1528,18 +1529,21 @@
   /**
    * The source for which the result is being reported.
    */
+  @override
   final Source source;
 
   /**
    * The parsed, but maybe not resolved Dart AST that changed as a result of
    * the analysis, or `null` if the AST was not changed.
    */
+  @override
   CompilationUnit parsedDartUnit;
 
   /**
    * The fully resolved Dart AST that changed as a result of the analysis, or
    * `null` if the AST was not changed.
    */
+  @override
   CompilationUnit resolvedDartUnit;
 
   /**
diff --git a/pkg/analyzer/lib/src/generated/error.dart b/pkg/analyzer/lib/src/generated/error.dart
index 446ca59..59879fc 100644
--- a/pkg/analyzer/lib/src/generated/error.dart
+++ b/pkg/analyzer/lib/src/generated/error.dart
@@ -85,7 +85,7 @@
   /**
    * The source in which the error occurred, or `null` if unknown.
    */
-  Source source;
+  final Source source;
 
   /**
    * The character offset from the beginning of the source (zero based) where
@@ -2482,8 +2482,10 @@
     // error.dart:
     //
     AnalysisOptionsErrorCode.PARSE_ERROR,
-    AnalysisOptionsWarningCode.UNSUPPORTED_OPTION_WITH_LEGAL_VALUE,
     AnalysisOptionsWarningCode.UNSUPPORTED_OPTION_WITH_LEGAL_VALUES,
+    AnalysisOptionsWarningCode.UNSUPPORTED_OPTION_WITH_LEGAL_VALUE,
+    AnalysisOptionsWarningCode.UNSUPPORTED_VALUE,
+    AnalysisOptionsWarningCode.UNRECOGNIZED_ERROR_CODE,
     CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_MISMATCH,
     CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH,
     CheckedModeCompileTimeErrorCode.CONST_FIELD_INITIALIZER_NOT_ASSIGNABLE,
@@ -2549,6 +2551,7 @@
     CompileTimeErrorCode.EXTENDS_NON_CLASS,
     CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS,
     CompileTimeErrorCode.EXTENDS_DEFERRED_CLASS,
+    CompileTimeErrorCode.EXTRA_ARGUMENT_TO_ASSERT,
     CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS,
     CompileTimeErrorCode.FIELD_INITIALIZED_BY_MULTIPLE_INITIALIZERS,
     CompileTimeErrorCode.FIELD_INITIALIZED_IN_PARAMETER_AND_INITIALIZER,
@@ -2664,6 +2667,7 @@
     CompileTimeErrorCode.YIELD_EACH_IN_NON_GENERATOR,
     CompileTimeErrorCode.YIELD_IN_NON_GENERATOR,
     HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE,
+    HintCode.CAN_BE_NULL_AFTER_NULL_AWARE,
     HintCode.DEAD_CODE,
     HintCode.DEAD_CODE_CATCH_FOLLOWING_CATCH,
     HintCode.DEAD_CODE_ON_CATCH_SUBTYPE,
@@ -2676,7 +2680,9 @@
     HintCode.IS_NOT_INT,
     HintCode.IMPORT_DEFERRED_LIBRARY_WITH_LOAD_FUNCTION,
     HintCode.INVALID_ASSIGNMENT,
+    HintCode.INVALID_USE_OF_PROTECTED_MEMBER,
     HintCode.MISSING_RETURN,
+    HintCode.NULL_AWARE_IN_CONDITION,
     HintCode.OVERRIDE_ON_NON_OVERRIDING_GETTER,
     HintCode.OVERRIDE_ON_NON_OVERRIDING_METHOD,
     HintCode.OVERRIDE_ON_NON_OVERRIDING_SETTER,
@@ -2688,6 +2694,7 @@
     HintCode.UNDEFINED_OPERATOR,
     HintCode.UNDEFINED_SETTER,
     HintCode.UNNECESSARY_CAST,
+    HintCode.UNNECESSARY_NO_SUCH_METHOD,
     HintCode.UNNECESSARY_TYPE_CHECK_FALSE,
     HintCode.UNNECESSARY_TYPE_CHECK_TRUE,
     HintCode.UNUSED_ELEMENT,
@@ -2699,7 +2706,6 @@
     HintCode.USE_OF_VOID_RESULT,
     HintCode.FILE_IMPORT_INSIDE_LIB_REFERENCES_FILE_OUTSIDE,
     HintCode.FILE_IMPORT_OUTSIDE_LIB_REFERENCES_FILE_INSIDE,
-    HintCode.NULL_AWARE_IN_CONDITION,
     HintCode.PACKAGE_IMPORT_CONTAINS_DOT_DOT,
     HtmlErrorCode.PARSE_ERROR,
     HtmlWarningCode.INVALID_URI,
@@ -2727,6 +2733,7 @@
     StaticTypeWarningCode.UNDEFINED_FUNCTION,
     StaticTypeWarningCode.UNDEFINED_GETTER,
     StaticTypeWarningCode.UNDEFINED_METHOD,
+    StaticTypeWarningCode.UNDEFINED_METHOD_WITH_CONSTRUCTOR,
     StaticTypeWarningCode.UNDEFINED_OPERATOR,
     StaticTypeWarningCode.UNDEFINED_SETTER,
     StaticTypeWarningCode.UNDEFINED_SUPER_GETTER,
@@ -2773,11 +2780,11 @@
     StaticWarningCode.INSTANCE_METHOD_NAME_COLLIDES_WITH_SUPERCLASS_STATIC,
     StaticWarningCode.INVALID_GETTER_OVERRIDE_RETURN_TYPE,
     StaticWarningCode.INVALID_METHOD_OVERRIDE_NAMED_PARAM_TYPE,
+    StaticWarningCode.INVALID_METHOD_OVERRIDE_TYPE_PARAMETERS,
+    StaticWarningCode.INVALID_METHOD_OVERRIDE_TYPE_PARAMETER_BOUND,
     StaticWarningCode.INVALID_METHOD_OVERRIDE_NORMAL_PARAM_TYPE,
     StaticWarningCode.INVALID_METHOD_OVERRIDE_OPTIONAL_PARAM_TYPE,
     StaticWarningCode.INVALID_METHOD_OVERRIDE_RETURN_TYPE,
-    StaticWarningCode.INVALID_METHOD_OVERRIDE_TYPE_PARAMETER_BOUND,
-    StaticWarningCode.INVALID_METHOD_OVERRIDE_TYPE_PARAMETERS,
     StaticWarningCode.INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_NAMED,
     StaticWarningCode.INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_POSITIONAL,
     StaticWarningCode.INVALID_OVERRIDE_NAMED,
@@ -2845,6 +2852,7 @@
     ParserErrorCode.ASSERT_DOES_NOT_TAKE_THROW,
     ParserErrorCode.ASSERT_DOES_NOT_TAKE_RETHROW,
     ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER,
+    ParserErrorCode.ASYNC_NOT_SUPPORTED,
     ParserErrorCode.BREAK_OUTSIDE_OF_LOOP,
     ParserErrorCode.CLASS_IN_CLASS,
     ParserErrorCode.COLON_IN_PLACE_OF_IN,
@@ -2908,6 +2916,7 @@
     ParserErrorCode.INVALID_CODE_POINT,
     ParserErrorCode.INVALID_COMMENT_REFERENCE,
     ParserErrorCode.INVALID_HEX_ESCAPE,
+    ParserErrorCode.INVALID_LITERAL_IN_CONFIGURATION,
     ParserErrorCode.INVALID_OPERATOR,
     ParserErrorCode.INVALID_OPERATOR_FOR_SUPER,
     ParserErrorCode.INVALID_STAR_AFTER_ASYNC,
@@ -3533,6 +3542,18 @@
       "A value of type '{0}' cannot be assigned to a variable of type '{1}'");
 
   /**
+   * This hint is generated anywhere where a member annotated with `@protected`
+   * is used outside an instance member of a subclass.
+   *
+   * Parameters:
+   * 0: the name of the member
+   * 1: the name of the defining class
+   */
+  static const HintCode INVALID_USE_OF_PROTECTED_MEMBER = const HintCode(
+      'INVALID_USE_OF_PROTECTED_MEMBER',
+      "The member '{0}' can only be used within instance members of subclasses of '{1}'");
+
+  /**
    * Generate a hint for methods or functions that have a return type, but do
    * not have a non-void return statement on all branches. At the end of methods
    * or functions with no return, Dart implicitly returns `null`, avoiding these
diff --git a/pkg/analyzer/lib/src/generated/incremental_resolver.dart b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
index 7cc84d3..fc8c860 100644
--- a/pkg/analyzer/lib/src/generated/incremental_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
@@ -1621,6 +1621,7 @@
       RecordingErrorListener errorListener = new RecordingErrorListener();
       Parser parser = new Parser(_unitSource, errorListener);
       AnalysisOptions options = _unitElement.context.analysisOptions;
+      parser.parseConditionalDirectives = options.enableConditionalDirectives;
       parser.parseGenericMethods = options.enableGenericMethods;
       CompilationUnit unit = parser.parseCompilationUnit(token);
       _newParseErrors = errorListener.errors;
diff --git a/pkg/analyzer/lib/src/generated/java_io.dart b/pkg/analyzer/lib/src/generated/java_io.dart
index dc054d0..2e0deb1 100644
--- a/pkg/analyzer/lib/src/generated/java_io.dart
+++ b/pkg/analyzer/lib/src/generated/java_io.dart
@@ -25,7 +25,9 @@
       this._path = pathContext.join(base._path, child);
     }
   }
+  @override
   int get hashCode => _path.hashCode;
+  @override
   bool operator ==(other) {
     return other is JavaFile && other._path == _path;
   }
@@ -101,6 +103,7 @@
   }
 
   String readAsStringSync() => _newFile().readAsStringSync();
+  @override
   String toString() => _path.toString();
   Uri toURI() {
     String path = getAbsolutePath();
diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart
index 8ec719a..9eff933 100644
--- a/pkg/analyzer/lib/src/generated/parser.dart
+++ b/pkg/analyzer/lib/src/generated/parser.dart
@@ -125,8 +125,6 @@
   'expectGt_0': new MethodTrampoline(0, (Parser target) => target._expectGt()),
   'expectKeyword_1': new MethodTrampoline(
       1, (Parser target, arg0) => target._expectKeyword(arg0)),
-  'expectSemicolon_0':
-      new MethodTrampoline(0, (Parser target) => target._expectSemicolon()),
   'findRange_2': new MethodTrampoline(
       2, (Parser target, arg0, arg1) => target._findRange(arg0, arg1)),
   'getCodeBlockRanges_1': new MethodTrampoline(
@@ -2510,7 +2508,7 @@
             commentAndMetadata.metadata,
             null,
             new VariableDeclarationList(null, null, keyword, null, variables),
-            _expectSemicolon());
+            _expect(TokenType.SEMICOLON));
       }
       _reportErrorForToken(
           ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken);
@@ -3797,10 +3795,9 @@
       }
       _reportErrorForToken(ParserErrorCode.EXPECTED_TOKEN,
           _currentToken.previous, [type.lexeme]);
-    } else {
-      _reportErrorForCurrentToken(
-          ParserErrorCode.EXPECTED_TOKEN, [type.lexeme]);
+      return _createSyntheticToken(TokenType.SEMICOLON);
     }
+    _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_TOKEN, [type.lexeme]);
     return _currentToken;
   }
 
@@ -3834,21 +3831,6 @@
   }
 
   /**
-   * If the current token is a semicolon, return it after advancing to the next
-   * token. Otherwise report an error and create a synthetic semicolon.
-   */
-  Token _expectSemicolon() {
-    // TODO(scheglov) consider pushing this behavior into [_expect]
-    if (_matches(TokenType.SEMICOLON)) {
-      return getAndAdvance();
-    } else {
-      _reportErrorForToken(
-          ParserErrorCode.EXPECTED_TOKEN, _currentToken.previous, [";"]);
-      return _createSyntheticToken(TokenType.SEMICOLON);
-    }
-  }
-
-  /**
    * Search the given list of [ranges] for a range that contains the given
    * [index]. Return the range that was found, or `null` if none of the ranges
    * contain the index.
@@ -5241,7 +5223,7 @@
             commentAndMetadata.comment,
             commentAndMetadata.metadata,
             new VariableDeclarationList(null, null, keyword, null, variables),
-            _expectSemicolon());
+            _expect(TokenType.SEMICOLON));
       }
       _reportErrorForToken(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken);
       return null;
@@ -5817,7 +5799,7 @@
     StringLiteral libraryUri = _parseUri();
     List<Configuration> configurations = _parseConfigurations();
     List<Combinator> combinators = _parseCombinators();
-    Token semicolon = _expectSemicolon();
+    Token semicolon = _expect(TokenType.SEMICOLON);
     return new ExportDirective(
         commentAndMetadata.comment,
         commentAndMetadata.metadata,
@@ -6040,12 +6022,12 @@
         _reportErrorForToken(
             ParserErrorCode.INVALID_AWAIT_IN_FOR, awaitKeyword);
       }
-      Token leftSeparator = _expectSemicolon();
+      Token leftSeparator = _expect(TokenType.SEMICOLON);
       Expression condition = null;
       if (!_matches(TokenType.SEMICOLON)) {
         condition = parseExpression2();
       }
-      Token rightSeparator = _expectSemicolon();
+      Token rightSeparator = _expect(TokenType.SEMICOLON);
       List<Expression> updaters = null;
       if (!_matches(TokenType.CLOSE_PAREN)) {
         updaters = _parseExpressionList();
@@ -6520,7 +6502,7 @@
       }
     }
     List<Combinator> combinators = _parseCombinators();
-    Token semicolon = _expectSemicolon();
+    Token semicolon = _expect(TokenType.SEMICOLON);
     return new ImportDirective(
         commentAndMetadata.comment,
         commentAndMetadata.metadata,
@@ -7154,7 +7136,8 @@
       _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT);
       return new EmptyStatement(_createSyntheticToken(TokenType.SEMICOLON));
     } else {
-      return new ExpressionStatement(parseExpression2(), _expectSemicolon());
+      return new ExpressionStatement(
+          parseExpression2(), _expect(TokenType.SEMICOLON));
     }
   }
 
@@ -9973,7 +9956,12 @@
   @override
   bool visitAdjacentStrings(AdjacentStrings node) {
     AdjacentStrings toNode = this._toNode as AdjacentStrings;
-    return _isEqualNodeLists(node.strings, toNode.strings);
+    if (_isEqualNodeLists(node.strings, toNode.strings)) {
+      toNode.staticType = node.staticType;
+      toNode.propagatedType = node.propagatedType;
+      return true;
+    }
+    return false;
   }
 
   @override
@@ -10523,7 +10511,9 @@
     if (_and(_isEqualNodes(node.function, toNode.function),
         _isEqualNodes(node.argumentList, toNode.argumentList))) {
       toNode.propagatedElement = node.propagatedElement;
+      toNode.propagatedInvokeType = node.propagatedInvokeType;
       toNode.propagatedType = node.propagatedType;
+      toNode.staticInvokeType = node.staticInvokeType;
       toNode.staticElement = node.staticElement;
       toNode.staticType = node.staticType;
       return true;
@@ -10785,7 +10775,9 @@
         _isEqualTokens(node.operator, toNode.operator),
         _isEqualNodes(node.methodName, toNode.methodName),
         _isEqualNodes(node.argumentList, toNode.argumentList))) {
+      toNode.propagatedInvokeType = node.propagatedInvokeType;
       toNode.propagatedType = node.propagatedType;
+      toNode.staticInvokeType = node.staticInvokeType;
       toNode.staticType = node.staticType;
       return true;
     }
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 45c75b2..491d391 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -206,6 +206,7 @@
   @override
   Object visitMethodInvocation(MethodInvocation node) {
     _checkForCanBeNullAfterNullAware(node.realTarget, node.operator);
+    _checkForInvalidProtectedMethodCalls(node);
     return super.visitMethodInvocation(node);
   }
 
@@ -237,6 +238,7 @@
   @override
   Object visitSimpleIdentifier(SimpleIdentifier node) {
     _checkForDeprecatedMemberUseAtIdentifier(node);
+    _checkForInvalidProtectedPropertyAccess(node);
     return super.visitSimpleIdentifier(node);
   }
 
@@ -608,6 +610,70 @@
   }
 
   /**
+   * Produces a hint if the given invocation is of a protected method outside
+   * a subclass instance method.
+   */
+  void _checkForInvalidProtectedMethodCalls(MethodInvocation node) {
+    Element element = node.methodName.bestElement;
+    if (element == null || !element.isProtected) {
+      return;
+    }
+
+    ClassElement definingClass = element.enclosingElement;
+
+    MethodDeclaration decl =
+        node.getAncestor((AstNode node) => node is MethodDeclaration);
+    if (decl == null) {
+      _errorReporter.reportErrorForNode(
+          HintCode.INVALID_USE_OF_PROTECTED_MEMBER,
+          node,
+          [node.methodName.toString(), definingClass.name]);
+      return;
+    }
+
+    ClassElement invokingClass = decl.element?.enclosingElement;
+    if (invokingClass != null) {
+      if (!_hasSuperClassOrMixin(invokingClass, definingClass.type)) {
+        _errorReporter.reportErrorForNode(
+            HintCode.INVALID_USE_OF_PROTECTED_MEMBER,
+            node,
+            [node.methodName.toString(), definingClass.name]);
+      }
+    }
+  }
+
+  /**
+   * Produces a hint if the given identifier is a protected field or getter
+   * accessed outside a subclass.
+   */
+  void _checkForInvalidProtectedPropertyAccess(SimpleIdentifier identifier) {
+    if (identifier.inDeclarationContext()) {
+      return;
+    }
+    Element element = identifier.bestElement;
+    if (element is PropertyAccessorElement &&
+        element.enclosingElement is ClassElement &&
+        (element.isProtected || element.variable.isProtected)) {
+      ClassElement definingClass = element.enclosingElement;
+      ClassDeclaration accessingClass =
+          identifier.getAncestor((AstNode node) => node is ClassDeclaration);
+
+      if (accessingClass == null) {
+        _errorReporter.reportErrorForNode(
+            HintCode.INVALID_USE_OF_PROTECTED_MEMBER,
+            identifier,
+            [identifier.name.toString(), definingClass.name]);
+      } else if (!_hasSuperClassOrMixin(
+          accessingClass.element, definingClass.type)) {
+        _errorReporter.reportErrorForNode(
+            HintCode.INVALID_USE_OF_PROTECTED_MEMBER,
+            identifier,
+            [identifier.name.toString(), definingClass.name]);
+      }
+    }
+  }
+
+  /**
    * Check that the imported library does not define a loadLibrary function. The import has already
    * been determined to be deferred when this is called.
    *
@@ -790,35 +856,6 @@
   }
 
   /**
-   * Check for the passed class declaration for the
-   * [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE] hint code.
-   *
-   * @param node the class declaration to check
-   * @return `true` if and only if a hint code is generated on the passed node
-   * See [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE].
-   */
-//  bool _checkForOverrideEqualsButNotHashCode(ClassDeclaration node) {
-//    ClassElement classElement = node.element;
-//    if (classElement == null) {
-//      return false;
-//    }
-//    MethodElement equalsOperatorMethodElement =
-//        classElement.getMethod(sc.TokenType.EQ_EQ.lexeme);
-//    if (equalsOperatorMethodElement != null) {
-//      PropertyAccessorElement hashCodeElement =
-//          classElement.getGetter(_HASHCODE_GETTER_NAME);
-//      if (hashCodeElement == null) {
-//        _errorReporter.reportErrorForNode(
-//            HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE,
-//            node.name,
-//            [classElement.displayName]);
-//        return true;
-//      }
-//    }
-//    return false;
-//  }
-
-  /**
    * Generate a hint for `noSuchMethod` methods that do nothing except of
    * calling another `noSuchMethod` that is not defined by `Object`.
    *
@@ -867,6 +904,35 @@
   }
 
   /**
+   * Check for the passed class declaration for the
+   * [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE] hint code.
+   *
+   * @param node the class declaration to check
+   * @return `true` if and only if a hint code is generated on the passed node
+   * See [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE].
+   */
+//  bool _checkForOverrideEqualsButNotHashCode(ClassDeclaration node) {
+//    ClassElement classElement = node.element;
+//    if (classElement == null) {
+//      return false;
+//    }
+//    MethodElement equalsOperatorMethodElement =
+//        classElement.getMethod(sc.TokenType.EQ_EQ.lexeme);
+//    if (equalsOperatorMethodElement != null) {
+//      PropertyAccessorElement hashCodeElement =
+//          classElement.getGetter(_HASHCODE_GETTER_NAME);
+//      if (hashCodeElement == null) {
+//        _errorReporter.reportErrorForNode(
+//            HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE,
+//            node.name,
+//            [classElement.displayName]);
+//        return true;
+//      }
+//    }
+//    return false;
+//  }
+
+  /**
    * Check for situations where the result of a method or function is used, when it returns 'void'.
    *
    * TODO(jwren) Many other situations of use could be covered. We currently cover the cases var x =
@@ -891,6 +957,24 @@
     return false;
   }
 
+  bool _hasSuperClassOrMixin(ClassElement element, InterfaceType type) {
+    List<ClassElement> seenClasses = <ClassElement>[];
+    while (element != null && !seenClasses.contains(element)) {
+      if (element.type == type) {
+        return true;
+      }
+
+      if (element.mixins.any((InterfaceType t) => t == type)) {
+        return true;
+      }
+
+      seenClasses.add(element);
+      element = element.supertype?.element;
+    }
+
+    return false;
+  }
+
   /**
    * Given a parenthesized expression, this returns the parent (or recursively grand-parent) of the
    * expression that is a parenthesized expression, but whose parent is not a parenthesized
@@ -2038,6 +2122,11 @@
  */
 class DeclarationResolver extends RecursiveAstVisitor<Object> {
   /**
+   * The analysis context containing the sources to be analyzed.
+   */
+  AnalysisContext _context;
+
+  /**
    * The elements that are reachable from the compilation unit element. When a
    * compilation unit has been resolved, this set should be empty.
    */
@@ -2078,6 +2167,7 @@
    * if the element model and compilation unit do not match each other.
    */
   void resolve(CompilationUnit unit, CompilationUnitElement element) {
+    _context = element.context;
     ElementGatherer gatherer = new ElementGatherer();
     element.accept(gatherer);
     _expectedElements = gatherer.elements;
@@ -2215,11 +2305,9 @@
     ExportElement exportElement;
     if (uri != null) {
       LibraryElement library = _enclosingUnit.library;
-      exportElement = _findExport(
-          node,
-          library.exports,
-          _enclosingUnit.context.sourceFactory
-              .resolveUri(_enclosingUnit.source, uri));
+      Source source = _enclosingUnit.context.sourceFactory
+          .resolveUri(_enclosingUnit.source, uri);
+      exportElement = _findExport(node, library.exports, source);
       node.element = exportElement;
     }
     super.visitExportDirective(node);
@@ -2356,11 +2444,9 @@
     ImportElement importElement;
     if (uri != null) {
       LibraryElement library = _enclosingUnit.library;
-      importElement = _findImport(
-          node,
-          library.imports,
-          _enclosingUnit.context.sourceFactory
-              .resolveUri(_enclosingUnit.source, uri));
+      Source source = _enclosingUnit.context.sourceFactory
+          .resolveUri(_enclosingUnit.source, uri);
+      importElement = _findImport(node, library.imports, source);
       node.element = importElement;
     }
     super.visitImportDirective(node);
@@ -2571,6 +2657,9 @@
    */
   ExportElement _findExport(
       ExportDirective node, List<ExportElement> exports, Source source) {
+    if (source == null || !_context.exists(source)) {
+      return null;
+    }
     for (ExportElement export in exports) {
       if (export.exportedLibrary.source == source) {
         return export;
@@ -2599,12 +2688,14 @@
 
   /**
    * Return the import element from the given list of [imports] whose library
-   * has the given [source] and that has the given [prefix]. Throw an
-   * [ElementMismatchException] if an element corresponding to the identifier
-   * cannot be found.
+   * has the given [source]. Throw an [ElementMismatchException] if an element
+   * corresponding to the [source] cannot be found.
    */
   ImportElement _findImport(
       ImportDirective node, List<ImportElement> imports, Source source) {
+    if (source == null || !_context.exists(source)) {
+      return null;
+    }
     SimpleIdentifier prefix = node.prefix;
     bool foundSource = false;
     for (ImportElement element in imports) {
@@ -4598,12 +4689,20 @@
   final TypeSystem _typeSystem;
 
   /**
+   * When no context type is available, this will track the least upper bound
+   * of all return statements in a lambda.
+   *
+   * This will always be kept in sync with [_returnStack].
+   */
+  final List<DartType> _inferredReturn = <DartType>[];
+
+  /**
    * A stack of return types for all of the enclosing
    * functions and methods.
    */
   // TODO(leafp) Handle the implicit union type for Futures
   // https://github.com/dart-lang/sdk/issues/25322
-  List<DartType> _returnStack = <DartType>[];
+  final List<DartType> _returnStack = <DartType>[];
 
   InferenceContext._(this._errorListener, TypeProvider typeProvider,
       this._typeSystem, this._inferenceHints)
@@ -4622,6 +4721,24 @@
       _returnStack.isNotEmpty ? _returnStack.last : null;
 
   /**
+   * Records the type of the expression of a return statement.
+   *
+   * This will be used for inferring a block bodied lambda, if no context
+   * type was available.
+   */
+  void addReturnOrYieldType(DartType type) {
+    if (_returnStack.isEmpty) {
+      return;
+    }
+    DartType context = _returnStack.last;
+    if (context == null || context.isDynamic) {
+      DartType inferred = _inferredReturn.last;
+      inferred = _typeSystem.getLeastUpperBound(_typeProvider, type, inferred);
+      _inferredReturn[_inferredReturn.length - 1] = inferred;
+    }
+  }
+
+  /**
    * Match type [t1] against type [t2] as follows.
    * If `t1 = I<dynamic, ..., dynamic>`, then look for a supertype
    * of t1 of the form `K<S0, ..., Sm>` where `t2 = K<S0', ..., Sm'>`
@@ -4634,19 +4751,31 @@
 
   /**
    * Pop a return type off of the return stack.
+   *
+   * Also record any inferred return type using [setType], unless this node
+   * already has a context type. This recorded type will be the least upper
+   * bound of all types added with [addReturnOrYieldType].
    */
-  void popReturnContext() {
-    assert(_returnStack.isNotEmpty);
+  void popReturnContext(BlockFunctionBody node) {
+    assert(_returnStack.isNotEmpty && _inferredReturn.isNotEmpty);
     if (_returnStack.isNotEmpty) {
       _returnStack.removeLast();
     }
+    if (_inferredReturn.isNotEmpty) {
+      DartType inferred = _inferredReturn.removeLast();
+      if (!inferred.isBottom) {
+        setType(node, inferred);
+      }
+    }
   }
 
   /**
-   * Push a [returnType] onto the return stack.
+   * Push a block function body's return type onto the return stack.
    */
-  void pushReturnContext(DartType returnType) {
+  void pushReturnContext(BlockFunctionBody node) {
+    DartType returnType = getType(node);
     _returnStack.add(returnType);
+    _inferredReturn.add(BottomTypeImpl.instance);
   }
 
   /**
@@ -7653,11 +7782,11 @@
   Object visitBlockFunctionBody(BlockFunctionBody node) {
     _overrideManager.enterScope();
     try {
-      inferenceContext.pushReturnContext(InferenceContext.getType(node));
+      inferenceContext.pushReturnContext(node);
       super.visitBlockFunctionBody(node);
     } finally {
       _overrideManager.exitScope();
-      inferenceContext.popReturnContext();
+      inferenceContext.popReturnContext(node);
     }
     return null;
   }
@@ -8135,10 +8264,8 @@
               matchFunctionTypeParameters(node.typeParameters, functionType);
           if (functionType is FunctionType) {
             _inferFormalParameterList(node.parameters, functionType);
-            DartType returnType = _computeReturnOrYieldType(
-                functionType.returnType,
-                _enclosingFunction.isGenerator,
-                _enclosingFunction.isAsynchronous);
+            DartType returnType =
+                _computeReturnOrYieldType(functionType.returnType);
             InferenceContext.setType(node.body, returnType);
           }
         }
@@ -8348,10 +8475,8 @@
     try {
       _currentFunctionBody = node.body;
       _enclosingFunction = node.element;
-      DartType returnType = _computeReturnOrYieldType(
-          _enclosingFunction.type?.returnType,
-          _enclosingFunction.isGenerator,
-          _enclosingFunction.isAsynchronous);
+      DartType returnType =
+          _computeReturnOrYieldType(_enclosingFunction.type?.returnType);
       InferenceContext.setType(node.body, returnType);
       super.visitMethodDeclaration(node);
     } finally {
@@ -8383,26 +8508,6 @@
     return null;
   }
 
-  void _inferArgumentTypesFromContext(InvocationExpression node) {
-    DartType contextType = node.staticInvokeType;
-    if (contextType is FunctionType) {
-      DartType originalType = node.function.staticType;
-      DartType returnContextType = InferenceContext.getType(node);
-      TypeSystem ts = typeSystem;
-      if (returnContextType != null &&
-          node.typeArguments == null &&
-          originalType is FunctionType &&
-          originalType.typeFormals.isNotEmpty &&
-          ts is StrongTypeSystemImpl) {
-
-        contextType = ts.inferGenericFunctionCall(typeProvider, originalType,
-            DartType.EMPTY_LIST, DartType.EMPTY_LIST, returnContextType);
-      }
-
-      InferenceContext.setType(node.argumentList, contextType);
-    }
-  }
-
   @override
   Object visitNamedExpression(NamedExpression node) {
     InferenceContext.setType(node.expression, InferenceContext.getType(node));
@@ -8464,8 +8569,19 @@
 
   @override
   Object visitReturnStatement(ReturnStatement node) {
-    InferenceContext.setType(node.expression, inferenceContext.returnContext);
-    return super.visitReturnStatement(node);
+    Expression e = node.expression;
+    InferenceContext.setType(e, inferenceContext.returnContext);
+    super.visitReturnStatement(node);
+    DartType type = e?.staticType;
+    // Generators cannot return values, so don't try to do any inference if
+    // we're processing erroneous code.
+    if (type != null && _enclosingFunction?.isGenerator == false) {
+      if (_enclosingFunction.isAsynchronous) {
+        type = type.flattenFutures(typeSystem);
+      }
+      inferenceContext.addReturnOrYieldType(type);
+    }
+    return null;
   }
 
   @override
@@ -8587,25 +8703,44 @@
 
   @override
   Object visitYieldStatement(YieldStatement node) {
+    Expression e = node.expression;
     DartType returnType = inferenceContext.returnContext;
-    if (returnType != null && _enclosingFunction != null) {
+    bool isGenerator = _enclosingFunction?.isGenerator ?? false;
+    if (returnType != null && isGenerator) {
       // If we're not in a generator ([a]sync*, then we shouldn't have a yield.
       // so don't infer
-      if (_enclosingFunction.isGenerator) {
-        // If this just a yield, then we just pass on the element type
-        DartType type = returnType;
-        if (node.star != null) {
-          // If this is a yield*, then we wrap the element return type
-          // If it's synchronous, we expect Iterable<T>, otherwise Stream<T>
-          InterfaceType wrapperType = _enclosingFunction.isSynchronous
-              ? typeProvider.iterableType
-              : typeProvider.streamType;
-          type = wrapperType.substitute4(<DartType>[type]);
-        }
-        InferenceContext.setType(node.expression, type);
+
+      // If this just a yield, then we just pass on the element type
+      DartType type = returnType;
+      if (node.star != null) {
+        // If this is a yield*, then we wrap the element return type
+        // If it's synchronous, we expect Iterable<T>, otherwise Stream<T>
+        InterfaceType wrapperType = _enclosingFunction.isSynchronous
+            ? typeProvider.iterableType
+            : typeProvider.streamType;
+        type = wrapperType.substitute4(<DartType>[type]);
+      }
+      InferenceContext.setType(e, type);
+    }
+    super.visitYieldStatement(node);
+    DartType type = e?.staticType;
+    if (type != null && isGenerator) {
+      // If this just a yield, then we just pass on the element type
+      if (node.star != null) {
+        // If this is a yield*, then we unwrap the element return type
+        // If it's synchronous, we expect Iterable<T>, otherwise Stream<T>
+        InterfaceType wrapperType = _enclosingFunction.isSynchronous
+            ? typeProvider.iterableType
+            : typeProvider.streamType;
+        List<DartType> candidates =
+            _findImplementedTypeArgument(type, wrapperType);
+        type = InterfaceTypeImpl.findMostSpecificType(candidates, typeSystem);
+      }
+      if (type != null) {
+        inferenceContext.addReturnOrYieldType(type);
       }
     }
-    return super.visitYieldStatement(node);
+    return null;
   }
 
   /**
@@ -8645,8 +8780,10 @@
    * values which should be returned or yielded as appropriate.  If a type
    * cannot be computed from the declared return type, return null.
    */
-  DartType _computeReturnOrYieldType(
-      DartType declaredType, bool isGenerator, bool isAsynchronous) {
+  DartType _computeReturnOrYieldType(DartType declaredType) {
+    bool isGenerator = _enclosingFunction.isGenerator;
+    bool isAsynchronous = _enclosingFunction.isAsynchronous;
+
     // Ordinary functions just return their declared types.
     if (!isGenerator && !isAsynchronous) {
       return declaredType;
@@ -8669,6 +8806,39 @@
   }
 
   /**
+   * Starting from t1, search its class hierarchy for types of the form
+   * `t2<R>`, and return a list of the resulting R's.
+   *
+   * For example, given t1 = `List<int>` and t2 = `Iterable<T>`, this will
+   * return [int].
+   */
+  // TODO(jmesserly): this is very similar to code used for flattening futures.
+  // The only difference is, because of a lack of TypeProvider, the other method
+  // has to match the Future type by its name and library. Here was are passed
+  // in the correct type.
+  List<DartType> _findImplementedTypeArgument(DartType t1, InterfaceType t2) {
+    List<DartType> result = <DartType>[];
+    HashSet<ClassElement> visitedClasses = new HashSet<ClassElement>();
+    void recurse(InterfaceTypeImpl type) {
+      if (type.element == t2.element && type.typeArguments.isNotEmpty) {
+        result.add(type.typeArguments[0]);
+      }
+      if (visitedClasses.add(type.element)) {
+        if (type.superclass != null) {
+          recurse(type.superclass);
+        }
+        type.mixins.forEach(recurse);
+        type.interfaces.forEach(recurse);
+        visitedClasses.remove(type.element);
+      }
+    }
+    if (t1 is InterfaceType) {
+      recurse(t1);
+    }
+    return result;
+  }
+
+  /**
    * The given expression is the expression used to compute the iterator for a
    * for-each statement. Attempt to compute the type of objects that will be
    * assigned to the loop variable and return that type. Return `null` if the
@@ -8730,6 +8900,25 @@
     return null;
   }
 
+  void _inferArgumentTypesFromContext(InvocationExpression node) {
+    DartType contextType = node.staticInvokeType;
+    if (contextType is FunctionType) {
+      DartType originalType = node.function.staticType;
+      DartType returnContextType = InferenceContext.getType(node);
+      TypeSystem ts = typeSystem;
+      if (returnContextType != null &&
+          node.typeArguments == null &&
+          originalType is FunctionType &&
+          originalType.typeFormals.isNotEmpty &&
+          ts is StrongTypeSystemImpl) {
+        contextType = ts.inferGenericFunctionCall(typeProvider, originalType,
+            DartType.EMPTY_LIST, DartType.EMPTY_LIST, returnContextType);
+      }
+
+      InferenceContext.setType(node.argumentList, contextType);
+    }
+  }
+
   void _inferFormalParameterList(FormalParameterList node, DartType type) {
     if (typeAnalyzer.inferFormalParameterList(node, type)) {
       // TODO(leafp): This gets dropped on the floor if we're in the field
@@ -11444,6 +11633,7 @@
   Object visitTypeName(TypeName node) {
     super.visitTypeName(node);
     Identifier typeName = node.name;
+    _setElement(typeName, null); // Clear old Elements from previous run.
     TypeArgumentList argumentList = node.typeArguments;
     Element element = nameScope.lookup(typeName, definingLibrary);
     if (element == null) {
@@ -11592,8 +11782,6 @@
     if (!elementValid) {
       if (element is MultiplyDefinedElement) {
         _setElement(typeName, element);
-      } else {
-        _setElement(typeName, null);
       }
       typeName.staticType = _undefinedType;
       node.type = _undefinedType;
@@ -11658,7 +11846,6 @@
               StaticWarningCode.NOT_A_TYPE, typeName, [typeName.name]);
         }
       }
-      _setElement(typeName, null);
       typeName.staticType = _dynamicType;
       node.type = _dynamicType;
       return null;
@@ -12159,25 +12346,19 @@
   }
 
   /**
-   * If the given [element] is not `null`, set `staticElement` of the
-   * [typeName] to it.  If the [typeName] is a prefixed identifier, and the
-   * prefix can be resolved to a not `null` element, set also the
-   * `staticElement` of the prefix.
+   * Records the new Element for a TypeName's Identifier.
+   *
+   * A null may be passed in to indicate that the element can't be resolved.
+   * (During a re-run of a task, it's important to clear any previous value
+   * of the element.)
    */
   void _setElement(Identifier typeName, Element element) {
     if (typeName is SimpleIdentifier) {
-      if (element != null) {
-        typeName.staticElement = element;
-      }
+      typeName.staticElement = element;
     } else if (typeName is PrefixedIdentifier) {
-      if (element != null) {
-        typeName.identifier.staticElement = element;
-      }
+      typeName.identifier.staticElement = element;
       SimpleIdentifier prefix = typeName.prefix;
-      Element prefixElement = nameScope.lookup(prefix, definingLibrary);
-      if (prefixElement != null) {
-        prefix.staticElement = prefixElement;
-      }
+      prefix.staticElement = nameScope.lookup(prefix, definingLibrary);
     }
   }
 
diff --git a/pkg/analyzer/lib/src/generated/sdk.dart b/pkg/analyzer/lib/src/generated/sdk.dart
index 7319a72..0670b7c 100644
--- a/pkg/analyzer/lib/src/generated/sdk.dart
+++ b/pkg/analyzer/lib/src/generated/sdk.dart
@@ -377,12 +377,14 @@
    * The short name of the library. This is the name used after 'dart:' in a
    * URI.
    */
+  @override
   final String shortName;
 
   /**
    * The path to the file defining the library. The path is relative to the
    * 'lib' directory within the SDK.
    */
+  @override
   String path = null;
 
   /**
@@ -390,6 +392,7 @@
    * in the libraries file all libraries are assumed to be shared between server
    * and client.
    */
+  @override
   String category = "Shared";
 
   /**
diff --git a/pkg/analyzer/lib/src/generated/sdk_io.dart b/pkg/analyzer/lib/src/generated/sdk_io.dart
index e7a9dea..6f03a84 100644
--- a/pkg/analyzer/lib/src/generated/sdk_io.dart
+++ b/pkg/analyzer/lib/src/generated/sdk_io.dart
@@ -9,8 +9,8 @@
 
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/src/context/context.dart';
-import 'package:analyzer/src/dart/scanner/scanner.dart';
 import 'package:analyzer/src/dart/scanner/reader.dart';
+import 'package:analyzer/src/dart/scanner/scanner.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/error.dart';
 import 'package:analyzer/src/generated/java_core.dart';
@@ -264,14 +264,6 @@
       _analysisContext = new SdkAnalysisContext();
       SourceFactory factory = new SourceFactory([new DartUriResolver(this)]);
       _analysisContext.sourceFactory = factory;
-      // Try to use summaries.
-      if (_useSummary) {
-        PackageBundle sdkBundle = _getSummarySdkBundle();
-        if (sdkBundle != null) {
-          _analysisContext.resultProvider =
-              new SdkSummaryResultProvider(_analysisContext, sdkBundle);
-        }
-      }
     }
     return _analysisContext;
   }
@@ -398,14 +390,17 @@
   List<String> get uris => _libraryMap.uris;
 
   /**
-   * Specify whether SDK summary should be used.  This property can only be set
-   * before [context] is invoked.
+   * Specify whether SDK summary should be used.
    */
   void set useSummary(bool use) {
-    if (_analysisContext != null) {
-      throw new StateError('SDK analysis context has been already created.');
-    }
     _useSummary = use;
+    if (_useSummary) {
+      PackageBundle sdkBundle = _getSummarySdkBundle();
+      if (sdkBundle != null) {
+        _analysisContext.resultProvider =
+            new SdkSummaryResultProvider(_analysisContext, sdkBundle);
+      }
+    }
   }
 
   /**
@@ -557,7 +552,9 @@
    */
   PackageBundle _getSummarySdkBundle() {
     String rootPath = directory.getAbsolutePath();
-    String path = pathos.join(rootPath, 'lib', '_internal', 'spec.sum');
+    String name =
+        context.analysisOptions.strongMode ? 'strong.sum' : 'spec.sum';
+    String path = pathos.join(rootPath, 'lib', '_internal', name);
     try {
       File file = new File(path);
       if (file.existsSync()) {
diff --git a/pkg/analyzer/lib/src/generated/source.dart b/pkg/analyzer/lib/src/generated/source.dart
index 8fcdad3..092671e 100644
--- a/pkg/analyzer/lib/src/generated/source.dart
+++ b/pkg/analyzer/lib/src/generated/source.dart
@@ -369,6 +369,7 @@
   @override
   final Uri uri;
 
+  @override
   final UriKind uriKind;
 
   NonExistingSource(this.fullName, this.uri, this.uriKind);
diff --git a/pkg/analyzer/lib/src/generated/source_io.dart b/pkg/analyzer/lib/src/generated/source_io.dart
index 4847d9a..49641c8 100644
--- a/pkg/analyzer/lib/src/generated/source_io.dart
+++ b/pkg/analyzer/lib/src/generated/source_io.dart
@@ -102,6 +102,7 @@
   /**
    * The URI from which this source was originally derived.
    */
+  @override
   final Uri uri;
 
   /**
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index c487796..b54bc04 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -461,37 +461,37 @@
       // node.
       return null;
     }
+    bool recordInference = false;
     ExecutableElementImpl functionElement =
         node.element as ExecutableElementImpl;
-    DartType computedType = _computeStaticReturnTypeOfFunctionExpression(node);
-    if (_strongMode) {
-      // In strong mode, we don't want to allow the function's return type to
-      // be bottom. If the surrounding context has a more precise type, we
-      // will push it down with inference, below. If not we want to use dynamic.
-      // TODO(jmesserly): should we  do this for the `null` literal always in
-      // strong mode, instead of handling it here?
-      if (computedType.isBottom) {
-        computedType = DynamicTypeImpl.instance;
-      }
 
-      DartType functionType = InferenceContext.getType(node);
-      if (functionType is FunctionType) {
-        functionType = _resolver.matchFunctionTypeParameters(
-            node.typeParameters, functionType);
-
-        if (functionType is FunctionType) {
-          DartType returnType = functionType.returnType;
-          if (computedType.isDynamic &&
-              !(returnType.isDynamic || returnType.isBottom)) {
-            computedType = returnType;
-            _resolver.inferenceContext.recordInference(node, functionType);
-          }
-        }
-      }
+    FunctionBody body = node.body;
+    DartType computedType;
+    if (body is ExpressionFunctionBody) {
+      computedType = _getStaticType(body.expression);
+    } else {
+      computedType = _dynamicType;
     }
+
+    // If we had a better type from the function body, use it.
+    //
+    // This helps in a few cases:
+    // * ExpressionFunctionBody, when the surrounding context had a better type.
+    // * BlockFunctionBody, if we inferred a type from yield/return.
+    // * we also normalize bottom to dynamic here.
+    if (_strongMode && (computedType.isBottom || computedType.isDynamic)) {
+      computedType = InferenceContext.getType(body) ?? _dynamicType;
+      recordInference = !computedType.isDynamic;
+    }
+
+    computedType = _computeReturnTypeOfFunction(body, computedType);
+
     functionElement.returnType = computedType;
     _recordPropagatedTypeOfFunction(functionElement, node.body);
-    _recordStaticType(node, node.element.type);
+    _recordStaticType(node, functionElement.type);
+    if (recordInference) {
+      _resolver.inferenceContext.recordInference(node, functionElement.type);
+    }
     return null;
   }
 
@@ -941,6 +941,7 @@
    */
   @override
   Object visitNullLiteral(NullLiteral node) {
+    // TODO(jmesserly): in strong mode, should we just use the context type?
     _recordStaticType(node, _typeProvider.bottomType);
     return null;
   }
@@ -1473,6 +1474,27 @@
   }
 
   /**
+   * Given a function body and its return type, compute the return type of
+   * the entire function, taking into account whether the function body
+   * is `sync*`, `async` or `async*`.
+   *
+   * See also [FunctionBody.isAsynchronous], [FunctionBody.isGenerator].
+   */
+  DartType _computeReturnTypeOfFunction(FunctionBody body, DartType type) {
+    if (body.isGenerator) {
+      InterfaceType genericType = body.isAsynchronous
+          ? _typeProvider.streamType
+          : _typeProvider.iterableType;
+      return genericType.substitute4(<DartType>[type]);
+    } else if (body.isAsynchronous) {
+      return _typeProvider.futureType
+          .substitute4(<DartType>[type.flattenFutures(_typeSystem)]);
+    } else {
+      return type;
+    }
+  }
+
+  /**
    * Compute the static return type of the method or function represented by the given element.
    *
    * @param element the element representing the method or function invoked by the given node
@@ -1514,38 +1536,6 @@
     return returnType.type;
   }
 
-  /**
-   * Given a function expression, compute the return type of the function. The return type of
-   * functions with a block body is `dynamicType`, with an expression body it is the type of
-   * the expression.
-   *
-   * @param node the function expression whose return type is to be computed
-   * @return the return type that was computed
-   */
-  DartType _computeStaticReturnTypeOfFunctionExpression(
-      FunctionExpression node) {
-    FunctionBody body = node.body;
-    if (body.isGenerator) {
-      if (body.isAsynchronous) {
-        return _typeProvider.streamDynamicType;
-      } else {
-        return _typeProvider.iterableDynamicType;
-      }
-    }
-    DartType type;
-    if (body is ExpressionFunctionBody) {
-      type = _getStaticType(body.expression);
-    } else {
-      type = _dynamicType;
-    }
-    if (body.isAsynchronous) {
-      return _typeProvider.futureType
-          .substitute4(<DartType>[type.flattenFutures(_typeSystem)]);
-    } else {
-      return type;
-    }
-  }
-
   DartType _findIteratedType(DartType type, DartType targetType) {
     // TODO(vsm): Use leafp's matchType here?
     // Set by _find if match is found
diff --git a/pkg/analyzer/lib/src/generated/testing/element_factory.dart b/pkg/analyzer/lib/src/generated/testing/element_factory.dart
index d5ac50f..2beeab4 100644
--- a/pkg/analyzer/lib/src/generated/testing/element_factory.dart
+++ b/pkg/analyzer/lib/src/generated/testing/element_factory.dart
@@ -251,6 +251,15 @@
           Identifier name) =>
       new FieldFormalParameterElementImpl.forNode(name);
 
+  /**
+   * Destroy any static state retained by [ElementFactory].  This should be
+   * called from the `setUp` method of any tests that use [ElementFactory], in
+   * order to ensure that state is not shared between multiple tests.
+   */
+  static void flushStaticState() {
+    _objectElement = null;
+  }
+
   static FunctionElementImpl functionElement(String functionName) =>
       functionElement4(functionName, null, null, null, null);
 
diff --git a/pkg/analyzer/lib/src/generated/visitors.dart b/pkg/analyzer/lib/src/generated/visitors.dart
index 31e5ddc..457d7f8 100644
--- a/pkg/analyzer/lib/src/generated/visitors.dart
+++ b/pkg/analyzer/lib/src/generated/visitors.dart
@@ -2,786 +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.
 
+@deprecated
 library analyzer.src.generated.visitors;
 
-import 'package:analyzer/dart/ast/ast.dart';
-
-/// An [AstVisitor] that delegates calls to visit methods to all [delegates]
-/// before calling [visitChildren].
-class DelegatingAstVisitor<T> implements AstVisitor<T> {
-  Iterable<AstVisitor<T>> _delegates;
-  DelegatingAstVisitor(this._delegates);
-
-  @override
-  T visitAdjacentStrings(AdjacentStrings node) {
-    _delegates.forEach((delegate) => delegate.visitAdjacentStrings(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitAnnotation(Annotation node) {
-    _delegates.forEach((delegate) => delegate.visitAnnotation(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitArgumentList(ArgumentList node) {
-    _delegates.forEach((delegate) => delegate.visitArgumentList(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitAsExpression(AsExpression node) {
-    _delegates.forEach((delegate) => delegate.visitAsExpression(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitAssertStatement(AssertStatement node) {
-    _delegates.forEach((delegate) => delegate.visitAssertStatement(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitAssignmentExpression(AssignmentExpression node) {
-    _delegates.forEach((delegate) => delegate.visitAssignmentExpression(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitAwaitExpression(AwaitExpression node) {
-    _delegates.forEach((delegate) => delegate.visitAwaitExpression(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitBinaryExpression(BinaryExpression node) {
-    _delegates.forEach((delegate) => delegate.visitBinaryExpression(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitBlock(Block node) {
-    _delegates.forEach((delegate) => delegate.visitBlock(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitBlockFunctionBody(BlockFunctionBody node) {
-    _delegates.forEach((delegate) => delegate.visitBlockFunctionBody(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitBooleanLiteral(BooleanLiteral node) {
-    _delegates.forEach((delegate) => delegate.visitBooleanLiteral(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitBreakStatement(BreakStatement node) {
-    _delegates.forEach((delegate) => delegate.visitBreakStatement(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitCascadeExpression(CascadeExpression node) {
-    _delegates.forEach((delegate) => delegate.visitCascadeExpression(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitCatchClause(CatchClause node) {
-    _delegates.forEach((delegate) => delegate.visitCatchClause(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitClassDeclaration(ClassDeclaration node) {
-    _delegates.forEach((delegate) => delegate.visitClassDeclaration(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitClassTypeAlias(ClassTypeAlias node) {
-    _delegates.forEach((delegate) => delegate.visitClassTypeAlias(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitComment(Comment node) {
-    _delegates.forEach((delegate) => delegate.visitComment(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitCommentReference(CommentReference node) {
-    _delegates.forEach((delegate) => delegate.visitCommentReference(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitCompilationUnit(CompilationUnit node) {
-    _delegates.forEach((delegate) => delegate.visitCompilationUnit(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitConditionalExpression(ConditionalExpression node) {
-    _delegates.forEach((delegate) => delegate.visitConditionalExpression(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitConfiguration(Configuration node) {
-    _delegates.forEach((delegate) => delegate.visitConfiguration(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitConstructorDeclaration(ConstructorDeclaration node) {
-    _delegates
-        .forEach((delegate) => delegate.visitConstructorDeclaration(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
-    _delegates
-        .forEach((delegate) => delegate.visitConstructorFieldInitializer(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitConstructorName(ConstructorName node) {
-    _delegates.forEach((delegate) => delegate.visitConstructorName(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitContinueStatement(ContinueStatement node) {
-    _delegates.forEach((delegate) => delegate.visitContinueStatement(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitDeclaredIdentifier(DeclaredIdentifier node) {
-    _delegates.forEach((delegate) => delegate.visitDeclaredIdentifier(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitDefaultFormalParameter(DefaultFormalParameter node) {
-    _delegates
-        .forEach((delegate) => delegate.visitDefaultFormalParameter(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitDoStatement(DoStatement node) {
-    _delegates.forEach((delegate) => delegate.visitDoStatement(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitDottedName(DottedName node) {
-    _delegates.forEach((delegate) => delegate.visitDottedName(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitDoubleLiteral(DoubleLiteral node) {
-    _delegates.forEach((delegate) => delegate.visitDoubleLiteral(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitEmptyFunctionBody(EmptyFunctionBody node) {
-    _delegates.forEach((delegate) => delegate.visitEmptyFunctionBody(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitEmptyStatement(EmptyStatement node) {
-    _delegates.forEach((delegate) => delegate.visitEmptyStatement(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitEnumConstantDeclaration(EnumConstantDeclaration node) {
-    _delegates
-        .forEach((delegate) => delegate.visitEnumConstantDeclaration(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitEnumDeclaration(EnumDeclaration node) {
-    _delegates.forEach((delegate) => delegate.visitEnumDeclaration(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitExportDirective(ExportDirective node) {
-    _delegates.forEach((delegate) => delegate.visitExportDirective(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitExpressionFunctionBody(ExpressionFunctionBody node) {
-    _delegates
-        .forEach((delegate) => delegate.visitExpressionFunctionBody(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitExpressionStatement(ExpressionStatement node) {
-    _delegates.forEach((delegate) => delegate.visitExpressionStatement(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitExtendsClause(ExtendsClause node) {
-    _delegates.forEach((delegate) => delegate.visitExtendsClause(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitFieldDeclaration(FieldDeclaration node) {
-    _delegates.forEach((delegate) => delegate.visitFieldDeclaration(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitFieldFormalParameter(FieldFormalParameter node) {
-    _delegates.forEach((delegate) => delegate.visitFieldFormalParameter(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitForEachStatement(ForEachStatement node) {
-    _delegates.forEach((delegate) => delegate.visitForEachStatement(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitFormalParameterList(FormalParameterList node) {
-    _delegates.forEach((delegate) => delegate.visitFormalParameterList(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitForStatement(ForStatement node) {
-    _delegates.forEach((delegate) => delegate.visitForStatement(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitFunctionDeclaration(FunctionDeclaration node) {
-    _delegates.forEach((delegate) => delegate.visitFunctionDeclaration(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitFunctionDeclarationStatement(FunctionDeclarationStatement node) {
-    _delegates.forEach(
-        (delegate) => delegate.visitFunctionDeclarationStatement(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitFunctionExpression(FunctionExpression node) {
-    _delegates.forEach((delegate) => delegate.visitFunctionExpression(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
-    _delegates.forEach(
-        (delegate) => delegate.visitFunctionExpressionInvocation(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitFunctionTypeAlias(FunctionTypeAlias node) {
-    _delegates.forEach((delegate) => delegate.visitFunctionTypeAlias(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
-    _delegates.forEach(
-        (delegate) => delegate.visitFunctionTypedFormalParameter(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitHideCombinator(HideCombinator node) {
-    _delegates.forEach((delegate) => delegate.visitHideCombinator(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitIfStatement(IfStatement node) {
-    _delegates.forEach((delegate) => delegate.visitIfStatement(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitImplementsClause(ImplementsClause node) {
-    _delegates.forEach((delegate) => delegate.visitImplementsClause(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitImportDirective(ImportDirective node) {
-    _delegates.forEach((delegate) => delegate.visitImportDirective(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitIndexExpression(IndexExpression node) {
-    _delegates.forEach((delegate) => delegate.visitIndexExpression(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitInstanceCreationExpression(InstanceCreationExpression node) {
-    _delegates
-        .forEach((delegate) => delegate.visitInstanceCreationExpression(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitIntegerLiteral(IntegerLiteral node) {
-    _delegates.forEach((delegate) => delegate.visitIntegerLiteral(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitInterpolationExpression(InterpolationExpression node) {
-    _delegates
-        .forEach((delegate) => delegate.visitInterpolationExpression(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitInterpolationString(InterpolationString node) {
-    _delegates.forEach((delegate) => delegate.visitInterpolationString(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitIsExpression(IsExpression node) {
-    _delegates.forEach((delegate) => delegate.visitIsExpression(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitLabel(Label node) {
-    _delegates.forEach((delegate) => delegate.visitLabel(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitLabeledStatement(LabeledStatement node) {
-    _delegates.forEach((delegate) => delegate.visitLabeledStatement(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitLibraryDirective(LibraryDirective node) {
-    _delegates.forEach((delegate) => delegate.visitLibraryDirective(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitLibraryIdentifier(LibraryIdentifier node) {
-    _delegates.forEach((delegate) => delegate.visitLibraryIdentifier(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitListLiteral(ListLiteral node) {
-    _delegates.forEach((delegate) => delegate.visitListLiteral(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitMapLiteral(MapLiteral node) {
-    _delegates.forEach((delegate) => delegate.visitMapLiteral(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitMapLiteralEntry(MapLiteralEntry node) {
-    _delegates.forEach((delegate) => delegate.visitMapLiteralEntry(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitMethodDeclaration(MethodDeclaration node) {
-    _delegates.forEach((delegate) => delegate.visitMethodDeclaration(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitMethodInvocation(MethodInvocation node) {
-    _delegates.forEach((delegate) => delegate.visitMethodInvocation(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitNamedExpression(NamedExpression node) {
-    _delegates.forEach((delegate) => delegate.visitNamedExpression(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitNativeClause(NativeClause node) {
-    _delegates.forEach((delegate) => delegate.visitNativeClause(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitNativeFunctionBody(NativeFunctionBody node) {
-    _delegates.forEach((delegate) => delegate.visitNativeFunctionBody(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitNullLiteral(NullLiteral node) {
-    _delegates.forEach((delegate) => delegate.visitNullLiteral(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitParenthesizedExpression(ParenthesizedExpression node) {
-    _delegates
-        .forEach((delegate) => delegate.visitParenthesizedExpression(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitPartDirective(PartDirective node) {
-    _delegates.forEach((delegate) => delegate.visitPartDirective(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitPartOfDirective(PartOfDirective node) {
-    _delegates.forEach((delegate) => delegate.visitPartOfDirective(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitPostfixExpression(PostfixExpression node) {
-    _delegates.forEach((delegate) => delegate.visitPostfixExpression(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitPrefixedIdentifier(PrefixedIdentifier node) {
-    _delegates.forEach((delegate) => delegate.visitPrefixedIdentifier(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitPrefixExpression(PrefixExpression node) {
-    _delegates.forEach((delegate) => delegate.visitPrefixExpression(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitPropertyAccess(PropertyAccess node) {
-    _delegates.forEach((delegate) => delegate.visitPropertyAccess(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitRedirectingConstructorInvocation(
-      RedirectingConstructorInvocation node) {
-    _delegates.forEach(
-        (delegate) => delegate.visitRedirectingConstructorInvocation(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitRethrowExpression(RethrowExpression node) {
-    _delegates.forEach((delegate) => delegate.visitRethrowExpression(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitReturnStatement(ReturnStatement node) {
-    _delegates.forEach((delegate) => delegate.visitReturnStatement(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitScriptTag(ScriptTag node) {
-    _delegates.forEach((delegate) => delegate.visitScriptTag(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitShowCombinator(ShowCombinator node) {
-    _delegates.forEach((delegate) => delegate.visitShowCombinator(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitSimpleFormalParameter(SimpleFormalParameter node) {
-    _delegates.forEach((delegate) => delegate.visitSimpleFormalParameter(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitSimpleIdentifier(SimpleIdentifier node) {
-    _delegates.forEach((delegate) => delegate.visitSimpleIdentifier(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitSimpleStringLiteral(SimpleStringLiteral node) {
-    _delegates.forEach((delegate) => delegate.visitSimpleStringLiteral(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitStringInterpolation(StringInterpolation node) {
-    _delegates.forEach((delegate) => delegate.visitStringInterpolation(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitSuperConstructorInvocation(SuperConstructorInvocation node) {
-    _delegates
-        .forEach((delegate) => delegate.visitSuperConstructorInvocation(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitSuperExpression(SuperExpression node) {
-    _delegates.forEach((delegate) => delegate.visitSuperExpression(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitSwitchCase(SwitchCase node) {
-    _delegates.forEach((delegate) => delegate.visitSwitchCase(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitSwitchDefault(SwitchDefault node) {
-    _delegates.forEach((delegate) => delegate.visitSwitchDefault(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitSwitchStatement(SwitchStatement node) {
-    _delegates.forEach((delegate) => delegate.visitSwitchStatement(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitSymbolLiteral(SymbolLiteral node) {
-    _delegates.forEach((delegate) => delegate.visitSymbolLiteral(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitThisExpression(ThisExpression node) {
-    _delegates.forEach((delegate) => delegate.visitThisExpression(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitThrowExpression(ThrowExpression node) {
-    _delegates.forEach((delegate) => delegate.visitThrowExpression(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
-    _delegates
-        .forEach((delegate) => delegate.visitTopLevelVariableDeclaration(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitTryStatement(TryStatement node) {
-    _delegates.forEach((delegate) => delegate.visitTryStatement(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitTypeArgumentList(TypeArgumentList node) {
-    _delegates.forEach((delegate) => delegate.visitTypeArgumentList(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitTypeName(TypeName node) {
-    _delegates.forEach((delegate) => delegate.visitTypeName(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitTypeParameter(TypeParameter node) {
-    _delegates.forEach((delegate) => delegate.visitTypeParameter(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitTypeParameterList(TypeParameterList node) {
-    _delegates.forEach((delegate) => delegate.visitTypeParameterList(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitVariableDeclaration(VariableDeclaration node) {
-    _delegates.forEach((delegate) => delegate.visitVariableDeclaration(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitVariableDeclarationList(VariableDeclarationList node) {
-    _delegates
-        .forEach((delegate) => delegate.visitVariableDeclarationList(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitVariableDeclarationStatement(VariableDeclarationStatement node) {
-    _delegates.forEach(
-        (delegate) => delegate.visitVariableDeclarationStatement(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitWhileStatement(WhileStatement node) {
-    _delegates.forEach((delegate) => delegate.visitWhileStatement(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitWithClause(WithClause node) {
-    _delegates.forEach((delegate) => delegate.visitWithClause(node));
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  T visitYieldStatement(YieldStatement node) {
-    _delegates.forEach((delegate) => delegate.visitYieldStatement(node));
-    node.visitChildren(this);
-    return null;
-  }
-}
+export 'package:analyzer/dart/ast/visitor.dart' show DelegatingAstVisitor;
diff --git a/pkg/analyzer/lib/src/services/lint.dart b/pkg/analyzer/lib/src/services/lint.dart
index 953741b..af20f59 100644
--- a/pkg/analyzer/lib/src/services/lint.dart
+++ b/pkg/analyzer/lib/src/services/lint.dart
@@ -5,10 +5,10 @@
 library analyzer.src.services.lint;
 
 import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/error.dart';
 import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/visitors.dart';
 import 'package:analyzer/src/task/model.dart';
 import 'package:analyzer/task/model.dart';
 
diff --git a/pkg/analyzer/lib/src/string_source.dart b/pkg/analyzer/lib/src/string_source.dart
index 3cfbd2e..04eb0a3 100644
--- a/pkg/analyzer/lib/src/string_source.dart
+++ b/pkg/analyzer/lib/src/string_source.dart
@@ -53,6 +53,7 @@
    * Return `true` if the given [object] is a string source that is equal to
    * this source.
    */
+  @override
   bool operator ==(Object object) {
     return object is StringSource &&
         object._contents == _contents &&
diff --git a/pkg/analyzer/lib/src/summary/base.dart b/pkg/analyzer/lib/src/summary/base.dart
index 1a1626e..acdb839 100644
--- a/pkg/analyzer/lib/src/summary/base.dart
+++ b/pkg/analyzer/lib/src/summary/base.dart
@@ -23,6 +23,20 @@
 }
 
 /**
+ * Annotation used in the summary IDL to indicate that a summary class can be
+ * the top level object in an encoded summary.
+ */
+class TopLevel {
+  /**
+   * If non-null, identifier that will be stored in bytes 4-7 of the file,
+   * prior all other file data.  Must be exactly 4 Latin1 characters.
+   */
+  final String fileIdentifier;
+
+  const TopLevel([this.fileIdentifier]);
+}
+
+/**
  * Instances of this class represent data that has been read from a summary.
  */
 abstract class SummaryClass {
diff --git a/pkg/analyzer/lib/src/summary/flat_buffers.dart b/pkg/analyzer/lib/src/summary/flat_buffers.dart
index c7a4f44..ba2c2ef 100644
--- a/pkg/analyzer/lib/src/summary/flat_buffers.dart
+++ b/pkg/analyzer/lib/src/summary/flat_buffers.dart
@@ -10,6 +10,21 @@
 import 'dart:typed_data';
 
 /**
+ * Reader of lists of boolean values.
+ *
+ * The returned unmodifiable lists lazily read values on access.
+ */
+class BoolListReader extends Reader<List<bool>> {
+  const BoolListReader();
+
+  @override
+  int get size => 4;
+
+  @override
+  List<bool> read(BufferPointer bp) => new _FbBoolList(bp.derefObject());
+}
+
+/**
  * The reader of booleans.
  */
 class BoolReader extends Reader<bool> {
@@ -246,12 +261,20 @@
   /**
    * Finish off the creation of the buffer.  The given [offset] is used as the
    * root object offset, and usually references directly or indirectly every
-   * written object.
+   * written object.  If [fileIdentifier] is specified (and not `null`), it is
+   * interpreted as a 4-byte Latin-1 encoded string that should be placed at
+   * bytes 4-7 of the file.
    */
-  Uint8List finish(Offset offset) {
-    _prepare(max(4, _maxAlign), 1);
+  Uint8List finish(Offset offset, [String fileIdentifier]) {
+    _prepare(max(4, _maxAlign), fileIdentifier == null ? 1 : 2);
     int alignedTail = _tail + ((-_tail) % _maxAlign);
     _setUint32AtTail(_buf, alignedTail, alignedTail - offset._tail);
+    if (fileIdentifier != null) {
+      for (int i = 0; i < 4; i++) {
+        _setUint8AtTail(
+            _buf, alignedTail - 4 - i, fileIdentifier.codeUnitAt(i));
+      }
+    }
     return _buf.buffer.asUint8List(_buf.lengthInBytes - alignedTail);
   }
 
@@ -327,6 +350,38 @@
   }
 
   /**
+   * Write the given list of boolean [values].
+   */
+  Offset writeListBool(List<bool> values) {
+    int bitLength = values.length;
+    int padding = (-bitLength) % 8;
+    int byteLength = (bitLength + padding) ~/ 8;
+    // Prepare the backing Uint8List.
+    Uint8List bytes = new Uint8List(byteLength + 1);
+    // Record every bit.
+    int byteIndex = 0;
+    int byte = 0;
+    int mask = 1;
+    for (int bitIndex = 0; bitIndex < bitLength; bitIndex++) {
+      if (bitIndex != 0 && (bitIndex % 8 == 0)) {
+        bytes[byteIndex++] = byte;
+        byte = 0;
+        mask = 1;
+      }
+      if (values[bitIndex]) {
+        byte |= mask;
+      }
+      mask <<= 1;
+    }
+    // Write the last byte, even if it may be on the padding.
+    bytes[byteIndex] = byte;
+    // Write the padding length.
+    bytes[byteLength] = padding;
+    // Write as a Uint8 list.
+    return writeListUint8(bytes);
+  }
+
+  /**
    * Write the given list of 64-bit float [values].
    */
   Offset writeListFloat64(List<double> values) {
@@ -637,7 +692,7 @@
 }
 
 /**
- * Reader of lists of 32-bit float values.
+ * Reader of lists of unsigned 32-bit integer values.
  *
  * The returned unmodifiable lists lazily read values on access.
  */
@@ -678,6 +733,40 @@
 }
 
 /**
+ * List of booleans backed by 8-bit unsigned integers.
+ */
+class _FbBoolList extends Object with ListMixin<bool> implements List<bool> {
+  final List<int> uint8List;
+  int _length;
+
+  _FbBoolList(BufferPointer bp)
+      : uint8List = new _FbGenericList<int>(const Uint8Reader(), bp);
+
+  @override
+  int get length {
+    if (_length == null) {
+      _length = (uint8List.length - 1) * 8 - uint8List.last;
+    }
+    return _length;
+  }
+
+  @override
+  void set length(int i) =>
+      throw new StateError('Attempt to modify immutable list');
+
+  @override
+  bool operator [](int i) {
+    int index = i ~/ 8;
+    int mask = 1 << i % 8;
+    return uint8List[index] & mask != 0;
+  }
+
+  @override
+  void operator []=(int i, bool e) =>
+      throw new StateError('Attempt to modify immutable list');
+}
+
+/**
  * The list backed by 64-bit values - Uint64 length and Float64.
  */
 class _FbFloat64List extends _FbList<double> {
diff --git a/pkg/analyzer/lib/src/summary/format.dart b/pkg/analyzer/lib/src/summary/format.dart
index 99dbbce..e5c4630 100644
--- a/pkg/analyzer/lib/src/summary/format.dart
+++ b/pkg/analyzer/lib/src/summary/format.dart
@@ -11,6 +11,45 @@
 import 'idl.dart' as idl;
 import 'dart:convert' as convert;
 
+class _IndexNameKindReader extends fb.Reader<idl.IndexNameKind> {
+  const _IndexNameKindReader() : super();
+
+  @override
+  int get size => 1;
+
+  @override
+  idl.IndexNameKind read(fb.BufferPointer bp) {
+    int index = const fb.Uint8Reader().read(bp);
+    return index < idl.IndexNameKind.values.length ? idl.IndexNameKind.values[index] : idl.IndexNameKind.topLevel;
+  }
+}
+
+class _IndexRelationKindReader extends fb.Reader<idl.IndexRelationKind> {
+  const _IndexRelationKindReader() : super();
+
+  @override
+  int get size => 1;
+
+  @override
+  idl.IndexRelationKind read(fb.BufferPointer bp) {
+    int index = const fb.Uint8Reader().read(bp);
+    return index < idl.IndexRelationKind.values.length ? idl.IndexRelationKind.values[index] : idl.IndexRelationKind.IS_EXTENDED_BY;
+  }
+}
+
+class _IndexSyntheticElementKindReader extends fb.Reader<idl.IndexSyntheticElementKind> {
+  const _IndexSyntheticElementKindReader() : super();
+
+  @override
+  int get size => 1;
+
+  @override
+  idl.IndexSyntheticElementKind read(fb.BufferPointer bp) {
+    int index = const fb.Uint8Reader().read(bp);
+    return index < idl.IndexSyntheticElementKind.values.length ? idl.IndexSyntheticElementKind.values[index] : idl.IndexSyntheticElementKind.notSynthetic;
+  }
+}
+
 class _ReferenceKindReader extends fb.Reader<idl.ReferenceKind> {
   const _ReferenceKindReader() : super();
 
@@ -20,7 +59,7 @@
   @override
   idl.ReferenceKind read(fb.BufferPointer bp) {
     int index = const fb.Uint8Reader().read(bp);
-    return idl.ReferenceKind.values[index];
+    return index < idl.ReferenceKind.values.length ? idl.ReferenceKind.values[index] : idl.ReferenceKind.classOrEnum;
   }
 }
 
@@ -33,7 +72,7 @@
   @override
   idl.UnlinkedConstOperation read(fb.BufferPointer bp) {
     int index = const fb.Uint8Reader().read(bp);
-    return idl.UnlinkedConstOperation.values[index];
+    return index < idl.UnlinkedConstOperation.values.length ? idl.UnlinkedConstOperation.values[index] : idl.UnlinkedConstOperation.pushInt;
   }
 }
 
@@ -46,7 +85,7 @@
   @override
   idl.UnlinkedConstructorInitializerKind read(fb.BufferPointer bp) {
     int index = const fb.Uint8Reader().read(bp);
-    return idl.UnlinkedConstructorInitializerKind.values[index];
+    return index < idl.UnlinkedConstructorInitializerKind.values.length ? idl.UnlinkedConstructorInitializerKind.values[index] : idl.UnlinkedConstructorInitializerKind.field;
   }
 }
 
@@ -59,7 +98,7 @@
   @override
   idl.UnlinkedExecutableKind read(fb.BufferPointer bp) {
     int index = const fb.Uint8Reader().read(bp);
-    return idl.UnlinkedExecutableKind.values[index];
+    return index < idl.UnlinkedExecutableKind.values.length ? idl.UnlinkedExecutableKind.values[index] : idl.UnlinkedExecutableKind.functionOrMethod;
   }
 }
 
@@ -72,7 +111,7 @@
   @override
   idl.UnlinkedParamKind read(fb.BufferPointer bp) {
     int index = const fb.Uint8Reader().read(bp);
-    return idl.UnlinkedParamKind.values[index];
+    return index < idl.UnlinkedParamKind.values.length ? idl.UnlinkedParamKind.values[index] : idl.UnlinkedParamKind.required;
   }
 }
 
@@ -83,6 +122,8 @@
   int _paramReference;
   int _reference;
   int _slot;
+  List<UnlinkedParamBuilder> _syntheticParams;
+  EntityRefBuilder _syntheticReturnType;
   List<EntityRefBuilder> _typeArguments;
 
   @override
@@ -174,6 +215,34 @@
   }
 
   @override
+  List<UnlinkedParamBuilder> get syntheticParams => _syntheticParams ??= <UnlinkedParamBuilder>[];
+
+  /**
+   * If this [EntityRef] is a reference to a function type whose
+   * [FunctionElement] is not in any library (e.g. a function type that was
+   * synthesized by a LUB computation), the function parameters.  Otherwise
+   * empty.
+   */
+  void set syntheticParams(List<UnlinkedParamBuilder> _value) {
+    assert(!_finished);
+    _syntheticParams = _value;
+  }
+
+  @override
+  EntityRefBuilder get syntheticReturnType => _syntheticReturnType;
+
+  /**
+   * If this [EntityRef] is a reference to a function type whose
+   * [FunctionElement] is not in any library (e.g. a function type that was
+   * synthesized by a LUB computation), the return type of the function.
+   * Otherwise `null`.
+   */
+  void set syntheticReturnType(EntityRefBuilder _value) {
+    assert(!_finished);
+    _syntheticReturnType = _value;
+  }
+
+  @override
   List<EntityRefBuilder> get typeArguments => _typeArguments ??= <EntityRefBuilder>[];
 
   /**
@@ -186,21 +255,31 @@
     _typeArguments = _value;
   }
 
-  EntityRefBuilder({List<int> implicitFunctionTypeIndices, int paramReference, int reference, int slot, List<EntityRefBuilder> typeArguments})
+  EntityRefBuilder({List<int> implicitFunctionTypeIndices, int paramReference, int reference, int slot, List<UnlinkedParamBuilder> syntheticParams, EntityRefBuilder syntheticReturnType, List<EntityRefBuilder> typeArguments})
     : _implicitFunctionTypeIndices = implicitFunctionTypeIndices,
       _paramReference = paramReference,
       _reference = reference,
       _slot = slot,
+      _syntheticParams = syntheticParams,
+      _syntheticReturnType = syntheticReturnType,
       _typeArguments = typeArguments;
 
   fb.Offset finish(fb.Builder fbBuilder) {
     assert(!_finished);
     _finished = true;
     fb.Offset offset_implicitFunctionTypeIndices;
+    fb.Offset offset_syntheticParams;
+    fb.Offset offset_syntheticReturnType;
     fb.Offset offset_typeArguments;
     if (!(_implicitFunctionTypeIndices == null || _implicitFunctionTypeIndices.isEmpty)) {
       offset_implicitFunctionTypeIndices = fbBuilder.writeListUint32(_implicitFunctionTypeIndices);
     }
+    if (!(_syntheticParams == null || _syntheticParams.isEmpty)) {
+      offset_syntheticParams = fbBuilder.writeList(_syntheticParams.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (_syntheticReturnType != null) {
+      offset_syntheticReturnType = _syntheticReturnType.finish(fbBuilder);
+    }
     if (!(_typeArguments == null || _typeArguments.isEmpty)) {
       offset_typeArguments = fbBuilder.writeList(_typeArguments.map((b) => b.finish(fbBuilder)).toList());
     }
@@ -217,6 +296,12 @@
     if (_slot != null && _slot != 0) {
       fbBuilder.addUint32(2, _slot);
     }
+    if (offset_syntheticParams != null) {
+      fbBuilder.addOffset(6, offset_syntheticParams);
+    }
+    if (offset_syntheticReturnType != null) {
+      fbBuilder.addOffset(5, offset_syntheticReturnType);
+    }
     if (offset_typeArguments != null) {
       fbBuilder.addOffset(1, offset_typeArguments);
     }
@@ -240,6 +325,8 @@
   int _paramReference;
   int _reference;
   int _slot;
+  List<idl.UnlinkedParam> _syntheticParams;
+  idl.EntityRef _syntheticReturnType;
   List<idl.EntityRef> _typeArguments;
 
   @override
@@ -267,6 +354,18 @@
   }
 
   @override
+  List<idl.UnlinkedParam> get syntheticParams {
+    _syntheticParams ??= const fb.ListReader<idl.UnlinkedParam>(const _UnlinkedParamReader()).vTableGet(_bp, 6, const <idl.UnlinkedParam>[]);
+    return _syntheticParams;
+  }
+
+  @override
+  idl.EntityRef get syntheticReturnType {
+    _syntheticReturnType ??= const _EntityRefReader().vTableGet(_bp, 5, null);
+    return _syntheticReturnType;
+  }
+
+  @override
   List<idl.EntityRef> get typeArguments {
     _typeArguments ??= const fb.ListReader<idl.EntityRef>(const _EntityRefReader()).vTableGet(_bp, 1, const <idl.EntityRef>[]);
     return _typeArguments;
@@ -281,6 +380,8 @@
     if (paramReference != 0) _result["paramReference"] = paramReference;
     if (reference != 0) _result["reference"] = reference;
     if (slot != 0) _result["slot"] = slot;
+    if (syntheticParams.isNotEmpty) _result["syntheticParams"] = syntheticParams.map((_value) => _value.toJson()).toList();
+    if (syntheticReturnType != null) _result["syntheticReturnType"] = syntheticReturnType.toJson();
     if (typeArguments.isNotEmpty) _result["typeArguments"] = typeArguments.map((_value) => _value.toJson()).toList();
     return _result;
   }
@@ -291,6 +392,8 @@
     "paramReference": paramReference,
     "reference": reference,
     "slot": slot,
+    "syntheticParams": syntheticParams,
+    "syntheticReturnType": syntheticReturnType,
     "typeArguments": typeArguments,
   };
 
@@ -656,7 +759,7 @@
 
   List<int> toBuffer() {
     fb.Builder fbBuilder = new fb.Builder();
-    return fbBuilder.finish(finish(fbBuilder));
+    return fbBuilder.finish(finish(fbBuilder), "LLib");
   }
 
   fb.Offset finish(fb.Builder fbBuilder) {
@@ -1143,6 +1246,8 @@
 
   List<LinkedLibraryBuilder> _linkedLibraries;
   List<String> _linkedLibraryUris;
+  int _majorVersion;
+  int _minorVersion;
   List<String> _unlinkedUnitHashes;
   List<UnlinkedUnitBuilder> _unlinkedUnits;
   List<String> _unlinkedUnitUris;
@@ -1171,6 +1276,32 @@
   }
 
   @override
+  int get majorVersion => _majorVersion ??= 0;
+
+  /**
+   * Major version of the summary format.  See
+   * [PackageBundleAssembler.currentMajorVersion].
+   */
+  void set majorVersion(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _majorVersion = _value;
+  }
+
+  @override
+  int get minorVersion => _minorVersion ??= 0;
+
+  /**
+   * Minor version of the summary format.  See
+   * [PackageBundleAssembler.currentMinorVersion].
+   */
+  void set minorVersion(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _minorVersion = _value;
+  }
+
+  @override
   List<String> get unlinkedUnitHashes => _unlinkedUnitHashes ??= <String>[];
 
   /**
@@ -1204,16 +1335,18 @@
     _unlinkedUnitUris = _value;
   }
 
-  PackageBundleBuilder({List<LinkedLibraryBuilder> linkedLibraries, List<String> linkedLibraryUris, List<String> unlinkedUnitHashes, List<UnlinkedUnitBuilder> unlinkedUnits, List<String> unlinkedUnitUris})
+  PackageBundleBuilder({List<LinkedLibraryBuilder> linkedLibraries, List<String> linkedLibraryUris, int majorVersion, int minorVersion, List<String> unlinkedUnitHashes, List<UnlinkedUnitBuilder> unlinkedUnits, List<String> unlinkedUnitUris})
     : _linkedLibraries = linkedLibraries,
       _linkedLibraryUris = linkedLibraryUris,
+      _majorVersion = majorVersion,
+      _minorVersion = minorVersion,
       _unlinkedUnitHashes = unlinkedUnitHashes,
       _unlinkedUnits = unlinkedUnits,
       _unlinkedUnitUris = unlinkedUnitUris;
 
   List<int> toBuffer() {
     fb.Builder fbBuilder = new fb.Builder();
-    return fbBuilder.finish(finish(fbBuilder));
+    return fbBuilder.finish(finish(fbBuilder), "PBdl");
   }
 
   fb.Offset finish(fb.Builder fbBuilder) {
@@ -1246,6 +1379,12 @@
     if (offset_linkedLibraryUris != null) {
       fbBuilder.addOffset(1, offset_linkedLibraryUris);
     }
+    if (_majorVersion != null && _majorVersion != 0) {
+      fbBuilder.addUint32(5, _majorVersion);
+    }
+    if (_minorVersion != null && _minorVersion != 0) {
+      fbBuilder.addUint32(6, _minorVersion);
+    }
     if (offset_unlinkedUnitHashes != null) {
       fbBuilder.addOffset(4, offset_unlinkedUnitHashes);
     }
@@ -1278,6 +1417,8 @@
 
   List<idl.LinkedLibrary> _linkedLibraries;
   List<String> _linkedLibraryUris;
+  int _majorVersion;
+  int _minorVersion;
   List<String> _unlinkedUnitHashes;
   List<idl.UnlinkedUnit> _unlinkedUnits;
   List<String> _unlinkedUnitUris;
@@ -1295,6 +1436,18 @@
   }
 
   @override
+  int get majorVersion {
+    _majorVersion ??= const fb.Uint32Reader().vTableGet(_bp, 5, 0);
+    return _majorVersion;
+  }
+
+  @override
+  int get minorVersion {
+    _minorVersion ??= const fb.Uint32Reader().vTableGet(_bp, 6, 0);
+    return _minorVersion;
+  }
+
+  @override
   List<String> get unlinkedUnitHashes {
     _unlinkedUnitHashes ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bp, 4, const <String>[]);
     return _unlinkedUnitHashes;
@@ -1319,6 +1472,8 @@
     Map<String, Object> _result = <String, Object>{};
     if (linkedLibraries.isNotEmpty) _result["linkedLibraries"] = linkedLibraries.map((_value) => _value.toJson()).toList();
     if (linkedLibraryUris.isNotEmpty) _result["linkedLibraryUris"] = linkedLibraryUris;
+    if (majorVersion != 0) _result["majorVersion"] = majorVersion;
+    if (minorVersion != 0) _result["minorVersion"] = minorVersion;
     if (unlinkedUnitHashes.isNotEmpty) _result["unlinkedUnitHashes"] = unlinkedUnitHashes;
     if (unlinkedUnits.isNotEmpty) _result["unlinkedUnits"] = unlinkedUnits.map((_value) => _value.toJson()).toList();
     if (unlinkedUnitUris.isNotEmpty) _result["unlinkedUnitUris"] = unlinkedUnitUris;
@@ -1329,6 +1484,8 @@
   Map<String, Object> toMap() => {
     "linkedLibraries": linkedLibraries,
     "linkedLibraryUris": linkedLibraryUris,
+    "majorVersion": majorVersion,
+    "minorVersion": minorVersion,
     "unlinkedUnitHashes": unlinkedUnitHashes,
     "unlinkedUnits": unlinkedUnits,
     "unlinkedUnitUris": unlinkedUnitUris,
@@ -1338,6 +1495,683 @@
   String toString() => convert.JSON.encode(toJson());
 }
 
+class PackageIndexBuilder extends Object with _PackageIndexMixin implements idl.PackageIndex {
+  bool _finished = false;
+
+  List<idl.IndexSyntheticElementKind> _elementKinds;
+  List<int> _elementOffsets;
+  List<int> _elementUnits;
+  List<String> _strings;
+  List<int> _unitLibraryUris;
+  List<UnitIndexBuilder> _units;
+  List<int> _unitUnitUris;
+
+  @override
+  List<idl.IndexSyntheticElementKind> get elementKinds => _elementKinds ??= <idl.IndexSyntheticElementKind>[];
+
+  /**
+   * Each item of this list corresponds to a unique referenced element.  It is
+   * the kind of the synthetic element.
+   */
+  void set elementKinds(List<idl.IndexSyntheticElementKind> _value) {
+    assert(!_finished);
+    _elementKinds = _value;
+  }
+
+  @override
+  List<int> get elementOffsets => _elementOffsets ??= <int>[];
+
+  /**
+   * Each item of this list corresponds to a unique referenced element.  It is
+   * the offset of the element name relative to the beginning of the file.  The
+   * list is sorted in ascending order, so that the client can quickly check
+   * whether an element is referenced in this [PackageIndex].
+   */
+  void set elementOffsets(List<int> _value) {
+    assert(!_finished);
+    assert(_value == null || _value.every((e) => e >= 0));
+    _elementOffsets = _value;
+  }
+
+  @override
+  List<int> get elementUnits => _elementUnits ??= <int>[];
+
+  /**
+   * Each item of this list corresponds to a unique referenced element.  It is
+   * the index into [unitLibraryUris] and [unitUnitUris] for the library
+   * specific unit where the element is declared.
+   */
+  void set elementUnits(List<int> _value) {
+    assert(!_finished);
+    assert(_value == null || _value.every((e) => e >= 0));
+    _elementUnits = _value;
+  }
+
+  @override
+  List<String> get strings => _strings ??= <String>[];
+
+  /**
+   * List of unique element strings used in this [PackageIndex].
+   */
+  void set strings(List<String> _value) {
+    assert(!_finished);
+    _strings = _value;
+  }
+
+  @override
+  List<int> get unitLibraryUris => _unitLibraryUris ??= <int>[];
+
+  /**
+   * Each item of this list corresponds to the library URI of a unique library
+   * specific unit referenced in the [PackageIndex].  It is an index into
+   * [strings] list.
+   */
+  void set unitLibraryUris(List<int> _value) {
+    assert(!_finished);
+    assert(_value == null || _value.every((e) => e >= 0));
+    _unitLibraryUris = _value;
+  }
+
+  @override
+  List<UnitIndexBuilder> get units => _units ??= <UnitIndexBuilder>[];
+
+  /**
+   * List of indexes of each unit in this [PackageIndex].
+   */
+  void set units(List<UnitIndexBuilder> _value) {
+    assert(!_finished);
+    _units = _value;
+  }
+
+  @override
+  List<int> get unitUnitUris => _unitUnitUris ??= <int>[];
+
+  /**
+   * Each item of this list corresponds to the unit URI of a unique library
+   * specific unit referenced in the [PackageIndex].  It is an index into
+   * [strings] list.
+   */
+  void set unitUnitUris(List<int> _value) {
+    assert(!_finished);
+    assert(_value == null || _value.every((e) => e >= 0));
+    _unitUnitUris = _value;
+  }
+
+  PackageIndexBuilder({List<idl.IndexSyntheticElementKind> elementKinds, List<int> elementOffsets, List<int> elementUnits, List<String> strings, List<int> unitLibraryUris, List<UnitIndexBuilder> units, List<int> unitUnitUris})
+    : _elementKinds = elementKinds,
+      _elementOffsets = elementOffsets,
+      _elementUnits = elementUnits,
+      _strings = strings,
+      _unitLibraryUris = unitLibraryUris,
+      _units = units,
+      _unitUnitUris = unitUnitUris;
+
+  List<int> toBuffer() {
+    fb.Builder fbBuilder = new fb.Builder();
+    return fbBuilder.finish(finish(fbBuilder), "Indx");
+  }
+
+  fb.Offset finish(fb.Builder fbBuilder) {
+    assert(!_finished);
+    _finished = true;
+    fb.Offset offset_elementKinds;
+    fb.Offset offset_elementOffsets;
+    fb.Offset offset_elementUnits;
+    fb.Offset offset_strings;
+    fb.Offset offset_unitLibraryUris;
+    fb.Offset offset_units;
+    fb.Offset offset_unitUnitUris;
+    if (!(_elementKinds == null || _elementKinds.isEmpty)) {
+      offset_elementKinds = fbBuilder.writeListUint8(_elementKinds.map((b) => b.index).toList());
+    }
+    if (!(_elementOffsets == null || _elementOffsets.isEmpty)) {
+      offset_elementOffsets = fbBuilder.writeListUint32(_elementOffsets);
+    }
+    if (!(_elementUnits == null || _elementUnits.isEmpty)) {
+      offset_elementUnits = fbBuilder.writeListUint32(_elementUnits);
+    }
+    if (!(_strings == null || _strings.isEmpty)) {
+      offset_strings = fbBuilder.writeList(_strings.map((b) => fbBuilder.writeString(b)).toList());
+    }
+    if (!(_unitLibraryUris == null || _unitLibraryUris.isEmpty)) {
+      offset_unitLibraryUris = fbBuilder.writeListUint32(_unitLibraryUris);
+    }
+    if (!(_units == null || _units.isEmpty)) {
+      offset_units = fbBuilder.writeList(_units.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (!(_unitUnitUris == null || _unitUnitUris.isEmpty)) {
+      offset_unitUnitUris = fbBuilder.writeListUint32(_unitUnitUris);
+    }
+    fbBuilder.startTable();
+    if (offset_elementKinds != null) {
+      fbBuilder.addOffset(5, offset_elementKinds);
+    }
+    if (offset_elementOffsets != null) {
+      fbBuilder.addOffset(1, offset_elementOffsets);
+    }
+    if (offset_elementUnits != null) {
+      fbBuilder.addOffset(0, offset_elementUnits);
+    }
+    if (offset_strings != null) {
+      fbBuilder.addOffset(6, offset_strings);
+    }
+    if (offset_unitLibraryUris != null) {
+      fbBuilder.addOffset(2, offset_unitLibraryUris);
+    }
+    if (offset_units != null) {
+      fbBuilder.addOffset(4, offset_units);
+    }
+    if (offset_unitUnitUris != null) {
+      fbBuilder.addOffset(3, offset_unitUnitUris);
+    }
+    return fbBuilder.endTable();
+  }
+}
+
+idl.PackageIndex readPackageIndex(List<int> buffer) {
+  fb.BufferPointer rootRef = new fb.BufferPointer.fromBytes(buffer);
+  return const _PackageIndexReader().read(rootRef);
+}
+
+class _PackageIndexReader extends fb.TableReader<_PackageIndexImpl> {
+  const _PackageIndexReader();
+
+  @override
+  _PackageIndexImpl createObject(fb.BufferPointer bp) => new _PackageIndexImpl(bp);
+}
+
+class _PackageIndexImpl extends Object with _PackageIndexMixin implements idl.PackageIndex {
+  final fb.BufferPointer _bp;
+
+  _PackageIndexImpl(this._bp);
+
+  List<idl.IndexSyntheticElementKind> _elementKinds;
+  List<int> _elementOffsets;
+  List<int> _elementUnits;
+  List<String> _strings;
+  List<int> _unitLibraryUris;
+  List<idl.UnitIndex> _units;
+  List<int> _unitUnitUris;
+
+  @override
+  List<idl.IndexSyntheticElementKind> get elementKinds {
+    _elementKinds ??= const fb.ListReader<idl.IndexSyntheticElementKind>(const _IndexSyntheticElementKindReader()).vTableGet(_bp, 5, const <idl.IndexSyntheticElementKind>[]);
+    return _elementKinds;
+  }
+
+  @override
+  List<int> get elementOffsets {
+    _elementOffsets ??= const fb.Uint32ListReader().vTableGet(_bp, 1, const <int>[]);
+    return _elementOffsets;
+  }
+
+  @override
+  List<int> get elementUnits {
+    _elementUnits ??= const fb.Uint32ListReader().vTableGet(_bp, 0, const <int>[]);
+    return _elementUnits;
+  }
+
+  @override
+  List<String> get strings {
+    _strings ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bp, 6, const <String>[]);
+    return _strings;
+  }
+
+  @override
+  List<int> get unitLibraryUris {
+    _unitLibraryUris ??= const fb.Uint32ListReader().vTableGet(_bp, 2, const <int>[]);
+    return _unitLibraryUris;
+  }
+
+  @override
+  List<idl.UnitIndex> get units {
+    _units ??= const fb.ListReader<idl.UnitIndex>(const _UnitIndexReader()).vTableGet(_bp, 4, const <idl.UnitIndex>[]);
+    return _units;
+  }
+
+  @override
+  List<int> get unitUnitUris {
+    _unitUnitUris ??= const fb.Uint32ListReader().vTableGet(_bp, 3, const <int>[]);
+    return _unitUnitUris;
+  }
+}
+
+abstract class _PackageIndexMixin implements idl.PackageIndex {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    if (elementKinds.isNotEmpty) _result["elementKinds"] = elementKinds.map((_value) => _value.toString().split('.')[1]).toList();
+    if (elementOffsets.isNotEmpty) _result["elementOffsets"] = elementOffsets;
+    if (elementUnits.isNotEmpty) _result["elementUnits"] = elementUnits;
+    if (strings.isNotEmpty) _result["strings"] = strings;
+    if (unitLibraryUris.isNotEmpty) _result["unitLibraryUris"] = unitLibraryUris;
+    if (units.isNotEmpty) _result["units"] = units.map((_value) => _value.toJson()).toList();
+    if (unitUnitUris.isNotEmpty) _result["unitUnitUris"] = unitUnitUris;
+    return _result;
+  }
+
+  @override
+  Map<String, Object> toMap() => {
+    "elementKinds": elementKinds,
+    "elementOffsets": elementOffsets,
+    "elementUnits": elementUnits,
+    "strings": strings,
+    "unitLibraryUris": unitLibraryUris,
+    "units": units,
+    "unitUnitUris": unitUnitUris,
+  };
+
+  @override
+  String toString() => convert.JSON.encode(toJson());
+}
+
+class UnitIndexBuilder extends Object with _UnitIndexMixin implements idl.UnitIndex {
+  bool _finished = false;
+
+  List<idl.IndexNameKind> _definedNameKinds;
+  List<int> _definedNameOffsets;
+  List<int> _definedNames;
+  int _unit;
+  List<bool> _usedElementIsQualifiedFlags;
+  List<idl.IndexRelationKind> _usedElementKinds;
+  List<int> _usedElementLengths;
+  List<int> _usedElementOffsets;
+  List<int> _usedElements;
+  List<idl.IndexRelationKind> _usedNameKinds;
+  List<int> _usedNameOffsets;
+  List<int> _usedNames;
+
+  @override
+  List<idl.IndexNameKind> get definedNameKinds => _definedNameKinds ??= <idl.IndexNameKind>[];
+
+  /**
+   * Each item of this list is the kind of an element defined in this unit.
+   */
+  void set definedNameKinds(List<idl.IndexNameKind> _value) {
+    assert(!_finished);
+    _definedNameKinds = _value;
+  }
+
+  @override
+  List<int> get definedNameOffsets => _definedNameOffsets ??= <int>[];
+
+  /**
+   * Each item of this list is the name offset of an element defined in this
+   * unit relative to the beginning of the file.
+   */
+  void set definedNameOffsets(List<int> _value) {
+    assert(!_finished);
+    assert(_value == null || _value.every((e) => e >= 0));
+    _definedNameOffsets = _value;
+  }
+
+  @override
+  List<int> get definedNames => _definedNames ??= <int>[];
+
+  /**
+   * Each item of this list corresponds to an element defined in this unit.  It
+   * is an index into [PackageIndex.strings] list.  The list is sorted in
+   * ascending order, so that the client can quickly find name definitions in
+   * this [UnitIndex].
+   */
+  void set definedNames(List<int> _value) {
+    assert(!_finished);
+    assert(_value == null || _value.every((e) => e >= 0));
+    _definedNames = _value;
+  }
+
+  @override
+  int get unit => _unit ??= 0;
+
+  /**
+   * Index into [PackageIndex.unitLibraryUris] and [PackageIndex.unitUnitUris]
+   * for the library specific unit that corresponds to this [UnitIndex].
+   */
+  void set unit(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _unit = _value;
+  }
+
+  @override
+  List<bool> get usedElementIsQualifiedFlags => _usedElementIsQualifiedFlags ??= <bool>[];
+
+  /**
+   * Each item of this list is the `true` if the corresponding element usage
+   * is qualified with some prefix.
+   */
+  void set usedElementIsQualifiedFlags(List<bool> _value) {
+    assert(!_finished);
+    _usedElementIsQualifiedFlags = _value;
+  }
+
+  @override
+  List<idl.IndexRelationKind> get usedElementKinds => _usedElementKinds ??= <idl.IndexRelationKind>[];
+
+  /**
+   * Each item of this list is the kind of the element usage.
+   */
+  void set usedElementKinds(List<idl.IndexRelationKind> _value) {
+    assert(!_finished);
+    _usedElementKinds = _value;
+  }
+
+  @override
+  List<int> get usedElementLengths => _usedElementLengths ??= <int>[];
+
+  /**
+   * Each item of this list is the length of the element usage.
+   */
+  void set usedElementLengths(List<int> _value) {
+    assert(!_finished);
+    assert(_value == null || _value.every((e) => e >= 0));
+    _usedElementLengths = _value;
+  }
+
+  @override
+  List<int> get usedElementOffsets => _usedElementOffsets ??= <int>[];
+
+  /**
+   * Each item of this list is the offset of the element usage relative to the
+   * beginning of the file.
+   */
+  void set usedElementOffsets(List<int> _value) {
+    assert(!_finished);
+    assert(_value == null || _value.every((e) => e >= 0));
+    _usedElementOffsets = _value;
+  }
+
+  @override
+  List<int> get usedElements => _usedElements ??= <int>[];
+
+  /**
+   * Each item of this list is the index into [PackageIndex.elementUnits] and
+   * [PackageIndex.elementOffsets].  The list is sorted in ascending order, so
+   * that the client can quickly find element references in this [UnitIndex].
+   */
+  void set usedElements(List<int> _value) {
+    assert(!_finished);
+    assert(_value == null || _value.every((e) => e >= 0));
+    _usedElements = _value;
+  }
+
+  @override
+  List<idl.IndexRelationKind> get usedNameKinds => _usedNameKinds ??= <idl.IndexRelationKind>[];
+
+  /**
+   * Each item of this list is the kind of the name usage.
+   */
+  void set usedNameKinds(List<idl.IndexRelationKind> _value) {
+    assert(!_finished);
+    _usedNameKinds = _value;
+  }
+
+  @override
+  List<int> get usedNameOffsets => _usedNameOffsets ??= <int>[];
+
+  /**
+   * Each item of this list is the offset of the name usage relative to the
+   * beginning of the file.
+   */
+  void set usedNameOffsets(List<int> _value) {
+    assert(!_finished);
+    assert(_value == null || _value.every((e) => e >= 0));
+    _usedNameOffsets = _value;
+  }
+
+  @override
+  List<int> get usedNames => _usedNames ??= <int>[];
+
+  /**
+   * Each item of this list is the index into [PackageIndex.strings] for a
+   * used name.  The list is sorted in ascending order, so that the client can
+   * quickly find name uses in this [UnitIndex].
+   */
+  void set usedNames(List<int> _value) {
+    assert(!_finished);
+    assert(_value == null || _value.every((e) => e >= 0));
+    _usedNames = _value;
+  }
+
+  UnitIndexBuilder({List<idl.IndexNameKind> definedNameKinds, List<int> definedNameOffsets, List<int> definedNames, int unit, List<bool> usedElementIsQualifiedFlags, List<idl.IndexRelationKind> usedElementKinds, List<int> usedElementLengths, List<int> usedElementOffsets, List<int> usedElements, List<idl.IndexRelationKind> usedNameKinds, List<int> usedNameOffsets, List<int> usedNames})
+    : _definedNameKinds = definedNameKinds,
+      _definedNameOffsets = definedNameOffsets,
+      _definedNames = definedNames,
+      _unit = unit,
+      _usedElementIsQualifiedFlags = usedElementIsQualifiedFlags,
+      _usedElementKinds = usedElementKinds,
+      _usedElementLengths = usedElementLengths,
+      _usedElementOffsets = usedElementOffsets,
+      _usedElements = usedElements,
+      _usedNameKinds = usedNameKinds,
+      _usedNameOffsets = usedNameOffsets,
+      _usedNames = usedNames;
+
+  fb.Offset finish(fb.Builder fbBuilder) {
+    assert(!_finished);
+    _finished = true;
+    fb.Offset offset_definedNameKinds;
+    fb.Offset offset_definedNameOffsets;
+    fb.Offset offset_definedNames;
+    fb.Offset offset_usedElementIsQualifiedFlags;
+    fb.Offset offset_usedElementKinds;
+    fb.Offset offset_usedElementLengths;
+    fb.Offset offset_usedElementOffsets;
+    fb.Offset offset_usedElements;
+    fb.Offset offset_usedNameKinds;
+    fb.Offset offset_usedNameOffsets;
+    fb.Offset offset_usedNames;
+    if (!(_definedNameKinds == null || _definedNameKinds.isEmpty)) {
+      offset_definedNameKinds = fbBuilder.writeListUint8(_definedNameKinds.map((b) => b.index).toList());
+    }
+    if (!(_definedNameOffsets == null || _definedNameOffsets.isEmpty)) {
+      offset_definedNameOffsets = fbBuilder.writeListUint32(_definedNameOffsets);
+    }
+    if (!(_definedNames == null || _definedNames.isEmpty)) {
+      offset_definedNames = fbBuilder.writeListUint32(_definedNames);
+    }
+    if (!(_usedElementIsQualifiedFlags == null || _usedElementIsQualifiedFlags.isEmpty)) {
+      offset_usedElementIsQualifiedFlags = fbBuilder.writeListBool(_usedElementIsQualifiedFlags);
+    }
+    if (!(_usedElementKinds == null || _usedElementKinds.isEmpty)) {
+      offset_usedElementKinds = fbBuilder.writeListUint8(_usedElementKinds.map((b) => b.index).toList());
+    }
+    if (!(_usedElementLengths == null || _usedElementLengths.isEmpty)) {
+      offset_usedElementLengths = fbBuilder.writeListUint32(_usedElementLengths);
+    }
+    if (!(_usedElementOffsets == null || _usedElementOffsets.isEmpty)) {
+      offset_usedElementOffsets = fbBuilder.writeListUint32(_usedElementOffsets);
+    }
+    if (!(_usedElements == null || _usedElements.isEmpty)) {
+      offset_usedElements = fbBuilder.writeListUint32(_usedElements);
+    }
+    if (!(_usedNameKinds == null || _usedNameKinds.isEmpty)) {
+      offset_usedNameKinds = fbBuilder.writeListUint8(_usedNameKinds.map((b) => b.index).toList());
+    }
+    if (!(_usedNameOffsets == null || _usedNameOffsets.isEmpty)) {
+      offset_usedNameOffsets = fbBuilder.writeListUint32(_usedNameOffsets);
+    }
+    if (!(_usedNames == null || _usedNames.isEmpty)) {
+      offset_usedNames = fbBuilder.writeListUint32(_usedNames);
+    }
+    fbBuilder.startTable();
+    if (offset_definedNameKinds != null) {
+      fbBuilder.addOffset(6, offset_definedNameKinds);
+    }
+    if (offset_definedNameOffsets != null) {
+      fbBuilder.addOffset(7, offset_definedNameOffsets);
+    }
+    if (offset_definedNames != null) {
+      fbBuilder.addOffset(5, offset_definedNames);
+    }
+    if (_unit != null && _unit != 0) {
+      fbBuilder.addUint32(0, _unit);
+    }
+    if (offset_usedElementIsQualifiedFlags != null) {
+      fbBuilder.addOffset(11, offset_usedElementIsQualifiedFlags);
+    }
+    if (offset_usedElementKinds != null) {
+      fbBuilder.addOffset(4, offset_usedElementKinds);
+    }
+    if (offset_usedElementLengths != null) {
+      fbBuilder.addOffset(1, offset_usedElementLengths);
+    }
+    if (offset_usedElementOffsets != null) {
+      fbBuilder.addOffset(2, offset_usedElementOffsets);
+    }
+    if (offset_usedElements != null) {
+      fbBuilder.addOffset(3, offset_usedElements);
+    }
+    if (offset_usedNameKinds != null) {
+      fbBuilder.addOffset(10, offset_usedNameKinds);
+    }
+    if (offset_usedNameOffsets != null) {
+      fbBuilder.addOffset(9, offset_usedNameOffsets);
+    }
+    if (offset_usedNames != null) {
+      fbBuilder.addOffset(8, offset_usedNames);
+    }
+    return fbBuilder.endTable();
+  }
+}
+
+class _UnitIndexReader extends fb.TableReader<_UnitIndexImpl> {
+  const _UnitIndexReader();
+
+  @override
+  _UnitIndexImpl createObject(fb.BufferPointer bp) => new _UnitIndexImpl(bp);
+}
+
+class _UnitIndexImpl extends Object with _UnitIndexMixin implements idl.UnitIndex {
+  final fb.BufferPointer _bp;
+
+  _UnitIndexImpl(this._bp);
+
+  List<idl.IndexNameKind> _definedNameKinds;
+  List<int> _definedNameOffsets;
+  List<int> _definedNames;
+  int _unit;
+  List<bool> _usedElementIsQualifiedFlags;
+  List<idl.IndexRelationKind> _usedElementKinds;
+  List<int> _usedElementLengths;
+  List<int> _usedElementOffsets;
+  List<int> _usedElements;
+  List<idl.IndexRelationKind> _usedNameKinds;
+  List<int> _usedNameOffsets;
+  List<int> _usedNames;
+
+  @override
+  List<idl.IndexNameKind> get definedNameKinds {
+    _definedNameKinds ??= const fb.ListReader<idl.IndexNameKind>(const _IndexNameKindReader()).vTableGet(_bp, 6, const <idl.IndexNameKind>[]);
+    return _definedNameKinds;
+  }
+
+  @override
+  List<int> get definedNameOffsets {
+    _definedNameOffsets ??= const fb.Uint32ListReader().vTableGet(_bp, 7, const <int>[]);
+    return _definedNameOffsets;
+  }
+
+  @override
+  List<int> get definedNames {
+    _definedNames ??= const fb.Uint32ListReader().vTableGet(_bp, 5, const <int>[]);
+    return _definedNames;
+  }
+
+  @override
+  int get unit {
+    _unit ??= const fb.Uint32Reader().vTableGet(_bp, 0, 0);
+    return _unit;
+  }
+
+  @override
+  List<bool> get usedElementIsQualifiedFlags {
+    _usedElementIsQualifiedFlags ??= const fb.BoolListReader().vTableGet(_bp, 11, const <bool>[]);
+    return _usedElementIsQualifiedFlags;
+  }
+
+  @override
+  List<idl.IndexRelationKind> get usedElementKinds {
+    _usedElementKinds ??= const fb.ListReader<idl.IndexRelationKind>(const _IndexRelationKindReader()).vTableGet(_bp, 4, const <idl.IndexRelationKind>[]);
+    return _usedElementKinds;
+  }
+
+  @override
+  List<int> get usedElementLengths {
+    _usedElementLengths ??= const fb.Uint32ListReader().vTableGet(_bp, 1, const <int>[]);
+    return _usedElementLengths;
+  }
+
+  @override
+  List<int> get usedElementOffsets {
+    _usedElementOffsets ??= const fb.Uint32ListReader().vTableGet(_bp, 2, const <int>[]);
+    return _usedElementOffsets;
+  }
+
+  @override
+  List<int> get usedElements {
+    _usedElements ??= const fb.Uint32ListReader().vTableGet(_bp, 3, const <int>[]);
+    return _usedElements;
+  }
+
+  @override
+  List<idl.IndexRelationKind> get usedNameKinds {
+    _usedNameKinds ??= const fb.ListReader<idl.IndexRelationKind>(const _IndexRelationKindReader()).vTableGet(_bp, 10, const <idl.IndexRelationKind>[]);
+    return _usedNameKinds;
+  }
+
+  @override
+  List<int> get usedNameOffsets {
+    _usedNameOffsets ??= const fb.Uint32ListReader().vTableGet(_bp, 9, const <int>[]);
+    return _usedNameOffsets;
+  }
+
+  @override
+  List<int> get usedNames {
+    _usedNames ??= const fb.Uint32ListReader().vTableGet(_bp, 8, const <int>[]);
+    return _usedNames;
+  }
+}
+
+abstract class _UnitIndexMixin implements idl.UnitIndex {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    if (definedNameKinds.isNotEmpty) _result["definedNameKinds"] = definedNameKinds.map((_value) => _value.toString().split('.')[1]).toList();
+    if (definedNameOffsets.isNotEmpty) _result["definedNameOffsets"] = definedNameOffsets;
+    if (definedNames.isNotEmpty) _result["definedNames"] = definedNames;
+    if (unit != 0) _result["unit"] = unit;
+    if (usedElementIsQualifiedFlags.isNotEmpty) _result["usedElementIsQualifiedFlags"] = usedElementIsQualifiedFlags;
+    if (usedElementKinds.isNotEmpty) _result["usedElementKinds"] = usedElementKinds.map((_value) => _value.toString().split('.')[1]).toList();
+    if (usedElementLengths.isNotEmpty) _result["usedElementLengths"] = usedElementLengths;
+    if (usedElementOffsets.isNotEmpty) _result["usedElementOffsets"] = usedElementOffsets;
+    if (usedElements.isNotEmpty) _result["usedElements"] = usedElements;
+    if (usedNameKinds.isNotEmpty) _result["usedNameKinds"] = usedNameKinds.map((_value) => _value.toString().split('.')[1]).toList();
+    if (usedNameOffsets.isNotEmpty) _result["usedNameOffsets"] = usedNameOffsets;
+    if (usedNames.isNotEmpty) _result["usedNames"] = usedNames;
+    return _result;
+  }
+
+  @override
+  Map<String, Object> toMap() => {
+    "definedNameKinds": definedNameKinds,
+    "definedNameOffsets": definedNameOffsets,
+    "definedNames": definedNames,
+    "unit": unit,
+    "usedElementIsQualifiedFlags": usedElementIsQualifiedFlags,
+    "usedElementKinds": usedElementKinds,
+    "usedElementLengths": usedElementLengths,
+    "usedElementOffsets": usedElementOffsets,
+    "usedElements": usedElements,
+    "usedNameKinds": usedNameKinds,
+    "usedNameOffsets": usedNameOffsets,
+    "usedNames": usedNames,
+  };
+
+  @override
+  String toString() => convert.JSON.encode(toJson());
+}
+
 class UnlinkedClassBuilder extends Object with _UnlinkedClassMixin implements idl.UnlinkedClass {
   bool _finished = false;
 
@@ -4969,7 +5803,7 @@
 
   List<int> toBuffer() {
     fb.Builder fbBuilder = new fb.Builder();
-    return fbBuilder.finish(finish(fbBuilder));
+    return fbBuilder.finish(finish(fbBuilder), "UPNS");
   }
 
   fb.Offset finish(fb.Builder fbBuilder) {
@@ -5782,7 +6616,7 @@
 
   List<int> toBuffer() {
     fb.Builder fbBuilder = new fb.Builder();
-    return fbBuilder.finish(finish(fbBuilder));
+    return fbBuilder.finish(finish(fbBuilder), "UUnt");
   }
 
   fb.Offset finish(fb.Builder fbBuilder) {
diff --git a/pkg/analyzer/lib/src/summary/format.fbs b/pkg/analyzer/lib/src/summary/format.fbs
new file mode 100644
index 0000000..63828ff
--- /dev/null
+++ b/pkg/analyzer/lib/src/summary/format.fbs
@@ -0,0 +1,1963 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// This file has been automatically generated.  Please do not edit it manually.
+// To regenerate the file, use the script "pkg/analyzer/tool/generate_files".
+
+
+/**
+ * Enum used to indicate the kind of a name in index.
+ */
+enum IndexNameKind : byte {
+  /**
+   * A top-level element.
+   */
+  topLevel,
+
+  /**
+   * A class member.
+   */
+  classMember
+}
+
+/**
+ * Enum used to indicate the kind of an index relation.
+ */
+enum IndexRelationKind : byte {
+  /**
+   * Left: class.
+   *   Is extended by.
+   * Right: other class declaration.
+   */
+  IS_EXTENDED_BY,
+
+  /**
+   * Left: class.
+   *   Is implemented by.
+   * Right: other class declaration.
+   */
+  IS_IMPLEMENTED_BY,
+
+  /**
+   * Left: class.
+   *   Is mixed into.
+   * Right: other class declaration.
+   */
+  IS_MIXED_IN_BY,
+
+  /**
+   * Left: method, property accessor, function, variable.
+   *   Is invoked at.
+   * Right: location.
+   */
+  IS_INVOKED_BY,
+
+  /**
+   * Left: any element.
+   *   Is referenced (and not invoked, read/written) at.
+   * Right: location.
+   */
+  IS_REFERENCED_BY
+}
+
+/**
+ * When we need to reference a synthetic element in [PackageIndex] we use a
+ * value of this enum to specify which kind of the synthetic element we
+ * actually reference.
+ */
+enum IndexSyntheticElementKind : byte {
+  /**
+   * Not a synthetic element.
+   */
+  notSynthetic,
+
+  /**
+   * The unnamed synthetic constructor a class element.
+   */
+  constructor,
+
+  /**
+   * The synthetic getter of a property introducing element.
+   */
+  getter,
+
+  /**
+   * The synthetic setter of a property introducing element.
+   */
+  setter
+}
+
+/**
+ * Enum used to indicate the kind of entity referred to by a
+ * [LinkedReference].
+ */
+enum ReferenceKind : byte {
+  /**
+   * The entity is a class or enum.
+   */
+  classOrEnum,
+
+  /**
+   * The entity is a constructor.
+   */
+  constructor,
+
+  /**
+   * The entity is a getter or setter inside a class.  Note: this is used in
+   * the case where a constant refers to a static const declared inside a
+   * class.
+   */
+  propertyAccessor,
+
+  /**
+   * The entity is a method.
+   */
+  method,
+
+  /**
+   * The `length` property access.
+   */
+  length,
+
+  /**
+   * The entity is a typedef.
+   */
+  typedef,
+
+  /**
+   * The entity is a local function.
+   */
+  function,
+
+  /**
+   * The entity is a local variable.
+   */
+  variable,
+
+  /**
+   * The entity is a top level function.
+   */
+  topLevelFunction,
+
+  /**
+   * The entity is a top level getter or setter.
+   */
+  topLevelPropertyAccessor,
+
+  /**
+   * The entity is a prefix.
+   */
+  prefix,
+
+  /**
+   * The entity being referred to does not exist.
+   */
+  unresolved
+}
+
+/**
+ * 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 : byte {
+  /**
+   * 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 constant constructor parameter with
+   * the name obtained from [UnlinkedConst.strings].
+   */
+  pushConstructorParameter,
+
+  /**
+   * 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 `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, pass them to the predefined Dart
+   * function `identical`, and push the result back onto the stack.
+   */
+  identical,
+
+  /**
+   * 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 the top value from the stack, evaluate `v.length`, and push the result
+   * back onto the stack.
+   */
+  length
+}
+
+/**
+ * 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 used to indicate the kind of a parameter.
+ */
+enum UnlinkedParamKind : byte {
+  /**
+   * Parameter is required.
+   */
+  required,
+
+  /**
+   * Parameter is positional optional (enclosed in `[]`)
+   */
+  positional,
+
+  /**
+   * Parameter is named optional (enclosed in `{}`)
+   */
+  named
+}
+
+/**
+ * Summary information about a reference to a an entity such as a type, top
+ * level executable, or executable within a class.
+ */
+table EntityRef {
+  /**
+   * If this is a reference to a function type implicitly defined by a
+   * function-typed parameter, a list of zero-based indices indicating the path
+   * from the entity referred to by [reference] to the appropriate type
+   * parameter.  Otherwise the empty list.
+   *
+   * If there are N indices in this list, then the entity being referred to is
+   * the function type implicitly defined by a function-typed parameter of a
+   * function-typed parameter, to N levels of nesting.  The first index in the
+   * list refers to the outermost level of nesting; for example if [reference]
+   * refers to the entity defined by:
+   *
+   *     void f(x, void g(y, z, int h(String w))) { ... }
+   *
+   * Then to refer to the function type implicitly defined by parameter `h`
+   * (which is parameter 2 of parameter 1 of `f`), then
+   * [implicitFunctionTypeIndices] should be [1, 2].
+   *
+   * Note that if the entity being referred to is a generic method inside a
+   * generic class, then the type arguments in [typeArguments] are applied
+   * first to the class and then to the method.
+   */
+  implicitFunctionTypeIndices:[uint] (id: 4);
+
+  /**
+   * If this is a reference to a type parameter, one-based index into the list
+   * of [UnlinkedTypeParam]s currently in effect.  Indexing is done using De
+   * Bruijn index conventions; that is, innermost parameters come first, and
+   * if a class or method has multiple parameters, they are indexed from right
+   * to left.  So for instance, if the enclosing declaration is
+   *
+   *     class C<T,U> {
+   *       m<V,W> {
+   *         ...
+   *       }
+   *     }
+   *
+   * Then [paramReference] values of 1, 2, 3, and 4 represent W, V, U, and T,
+   * respectively.
+   *
+   * If the type being referred to is not a type parameter, [paramReference] is
+   * zero.
+   */
+  paramReference:uint (id: 3);
+
+  /**
+   * Index into [UnlinkedUnit.references] for the entity being referred to, or
+   * zero if this is a reference to a type parameter.
+   */
+  reference:uint (id: 0);
+
+  /**
+   * If this [EntityRef] is contained within [LinkedUnit.types], slot id (which
+   * is unique within the compilation unit) identifying the target of type
+   * propagation or type inference with which this [EntityRef] is associated.
+   *
+   * Otherwise zero.
+   */
+  slot:uint (id: 2);
+
+  /**
+   * If this [EntityRef] is a reference to a function type whose
+   * [FunctionElement] is not in any library (e.g. a function type that was
+   * synthesized by a LUB computation), the function parameters.  Otherwise
+   * empty.
+   */
+  syntheticParams:[UnlinkedParam] (id: 6);
+
+  /**
+   * If this [EntityRef] is a reference to a function type whose
+   * [FunctionElement] is not in any library (e.g. a function type that was
+   * synthesized by a LUB computation), the return type of the function.
+   * Otherwise `null`.
+   */
+  syntheticReturnType:EntityRef (id: 5);
+
+  /**
+   * If this is an instantiation of a generic type or generic executable, the
+   * type arguments used to instantiate it.  Trailing type arguments of type
+   * `dynamic` are omitted.
+   */
+  typeArguments:[EntityRef] (id: 1);
+}
+
+/**
+ * Information about a dependency that exists between one library and another
+ * due to an "import" declaration.
+ */
+table LinkedDependency {
+  /**
+   * URI for the compilation units listed in the library's `part` declarations.
+   * These URIs are relative to the importing library.
+   */
+  parts:[string] (id: 1);
+
+  /**
+   * The relative URI of the dependent library.  This URI is relative to the
+   * importing library, even if there are intervening `export` declarations.
+   * So, for example, if `a.dart` imports `b/c.dart` and `b/c.dart` exports
+   * `d/e.dart`, the URI listed for `a.dart`'s dependency on `e.dart` will be
+   * `b/d/e.dart`.
+   */
+  uri:string (id: 0);
+}
+
+/**
+ * Information about a single name in the export namespace of the library that
+ * is not in the public namespace.
+ */
+table LinkedExportName {
+  /**
+   * Index into [LinkedLibrary.dependencies] for the library in which the
+   * entity is defined.
+   */
+  dependency:uint (id: 0);
+
+  /**
+   * The kind of the entity being referred to.
+   */
+  kind:ReferenceKind (id: 3);
+
+  /**
+   * Name of the exported entity.  For an exported setter, this name includes
+   * the trailing '='.
+   */
+  name:string (id: 1);
+
+  /**
+   * Integer index indicating which unit in the exported library contains the
+   * definition of the entity.  As with indices into [LinkedLibrary.units],
+   * zero represents the defining compilation unit, and nonzero values
+   * represent parts in the order of the corresponding `part` declarations.
+   */
+  unit:uint (id: 2);
+}
+
+/**
+ * Linked summary of a library.
+ */
+table LinkedLibrary {
+  /**
+   * The libraries that this library depends on (either via an explicit import
+   * statement or via the implicit dependencies on `dart:core` and
+   * `dart:async`).  The first element of this array is a pseudo-dependency
+   * representing the library itself (it is also used for `dynamic` and
+   * `void`).  This is followed by elements representing "prelinked"
+   * dependencies (direct imports and the transitive closure of exports).
+   * After the prelinked dependencies are elements representing "linked"
+   * dependencies.
+   *
+   * A library is only included as a "linked" dependency if it is a true
+   * dependency (e.g. a propagated or inferred type or constant value
+   * implicitly refers to an element declared in the library) or
+   * anti-dependency (e.g. the result of type propagation or type inference
+   * depends on the lack of a certain declaration in the library).
+   */
+  dependencies:[LinkedDependency] (id: 0);
+
+  /**
+   * Information about entities in the export namespace of the library that are
+   * not in the public namespace of the library (that is, entities that are
+   * brought into the namespace via `export` directives).
+   *
+   * Sorted by name.
+   */
+  exportNames:[LinkedExportName] (id: 4);
+
+  /**
+   * For each import in [UnlinkedUnit.imports], an index into [dependencies]
+   * of the library being imported.
+   */
+  importDependencies:[uint] (id: 1);
+
+  /**
+   * The number of elements in [dependencies] which are not "linked"
+   * dependencies (that is, the number of libraries in the direct imports plus
+   * the transitive closure of exports, plus the library itself).
+   */
+  numPrelinkedDependencies:uint (id: 2);
+
+  /**
+   * The linked summary of all the compilation units constituting the
+   * library.  The summary of the defining compilation unit is listed first,
+   * followed by the summary of each part, in the order of the `part`
+   * declarations in the defining compilation unit.
+   */
+  units:[LinkedUnit] (id: 3);
+}
+
+/**
+ * Information about the resolution of an [UnlinkedReference].
+ */
+table LinkedReference {
+  /**
+   * If this [LinkedReference] doesn't have an associated [UnlinkedReference],
+   * and the entity being referred to is contained within another entity, index
+   * of the containing entity.  This behaves similarly to
+   * [UnlinkedReference.prefixReference], however it is only used for class
+   * members, not for prefixed imports.
+   *
+   * Containing references must always point backward; that is, for all i, if
+   * LinkedUnit.references[i].containingReference != 0, then
+   * LinkedUnit.references[i].containingReference < i.
+   */
+  containingReference:uint (id: 5);
+
+  /**
+   * Index into [LinkedLibrary.dependencies] indicating which imported library
+   * declares the entity being referred to.
+   *
+   * Zero if this entity is contained within another entity (e.g. a class
+   * member), or if [kind] is [ReferenceKind.prefix].
+   */
+  dependency:uint (id: 1);
+
+  /**
+   * The kind of the entity being referred to.  For the pseudo-types `dynamic`
+   * and `void`, the kind is [ReferenceKind.classOrEnum].
+   */
+  kind:ReferenceKind (id: 2);
+
+  /**
+   * If [kind] is [ReferenceKind.function] (that is, the entity being referred
+   * to is a local function), the index of the function within
+   * [UnlinkedExecutable.localFunctions].  If [kind] is
+   * [ReferenceKind.variable], the index of the variable within
+   * [UnlinkedExecutable.localVariables].  Otherwise zero.
+   */
+  localIndex:uint (id: 6);
+
+  /**
+   * If this [LinkedReference] doesn't have an associated [UnlinkedReference],
+   * name of the entity being referred to.  For the pseudo-type `dynamic`, the
+   * string is "dynamic".  For the pseudo-type `void`, the string is "void".
+   */
+  name:string (id: 3);
+
+  /**
+   * If the entity being referred to is generic, the number of type parameters
+   * it declares (does not include type parameters of enclosing entities).
+   * Otherwise zero.
+   */
+  numTypeParameters:uint (id: 4);
+
+  /**
+   * Integer index indicating which unit in the imported library contains the
+   * definition of the entity.  As with indices into [LinkedLibrary.units],
+   * zero represents the defining compilation unit, and nonzero values
+   * represent parts in the order of the corresponding `part` declarations.
+   *
+   * Zero if this entity is contained within another entity (e.g. a class
+   * member).
+   */
+  unit:uint (id: 0);
+}
+
+/**
+ * Linked summary of a compilation unit.
+ */
+table LinkedUnit {
+  /**
+   * Information about the resolution of references within the compilation
+   * unit.  Each element of [UnlinkedUnit.references] has a corresponding
+   * element in this list (at the same index).  If this list has additional
+   * elements beyond the number of elements in [UnlinkedUnit.references], those
+   * additional elements are references that are only referred to implicitly
+   * (e.g. elements involved in inferred or propagated types).
+   */
+  references:[LinkedReference] (id: 0);
+
+  /**
+   * List associating slot ids found inside the unlinked summary for the
+   * compilation unit with propagated and inferred types.
+   */
+  types:[EntityRef] (id: 1);
+}
+
+/**
+ * Summary information about a package.
+ */
+table PackageBundle {
+  /**
+   * Linked libraries.
+   */
+  linkedLibraries:[LinkedLibrary] (id: 0);
+
+  /**
+   * The list of URIs of items in [linkedLibraries], e.g. `dart:core` or
+   * `package:foo/bar.dart`.
+   */
+  linkedLibraryUris:[string] (id: 1);
+
+  /**
+   * Major version of the summary format.  See
+   * [PackageBundleAssembler.currentMajorVersion].
+   */
+  majorVersion:uint (id: 5);
+
+  /**
+   * Minor version of the summary format.  See
+   * [PackageBundleAssembler.currentMinorVersion].
+   */
+  minorVersion:uint (id: 6);
+
+  /**
+   * List of MD5 hashes of the files listed in [unlinkedUnitUris].  Each hash
+   * is encoded as a hexadecimal string using lower case letters.
+   */
+  unlinkedUnitHashes:[string] (id: 4);
+
+  /**
+   * Unlinked information for the compilation units constituting the package.
+   */
+  unlinkedUnits:[UnlinkedUnit] (id: 2);
+
+  /**
+   * The list of URIs of items in [unlinkedUnits], e.g. `dart:core/bool.dart`.
+   */
+  unlinkedUnitUris:[string] (id: 3);
+}
+
+/**
+ * Index information about a package.
+ */
+table PackageIndex {
+  /**
+   * Each item of this list corresponds to a unique referenced element.  It is
+   * the kind of the synthetic element.
+   */
+  elementKinds:[IndexSyntheticElementKind] (id: 5);
+
+  /**
+   * Each item of this list corresponds to a unique referenced element.  It is
+   * the offset of the element name relative to the beginning of the file.  The
+   * list is sorted in ascending order, so that the client can quickly check
+   * whether an element is referenced in this [PackageIndex].
+   */
+  elementOffsets:[uint] (id: 1);
+
+  /**
+   * Each item of this list corresponds to a unique referenced element.  It is
+   * the index into [unitLibraryUris] and [unitUnitUris] for the library
+   * specific unit where the element is declared.
+   */
+  elementUnits:[uint] (id: 0);
+
+  /**
+   * List of unique element strings used in this [PackageIndex].
+   */
+  strings:[string] (id: 6);
+
+  /**
+   * Each item of this list corresponds to the library URI of a unique library
+   * specific unit referenced in the [PackageIndex].  It is an index into
+   * [strings] list.
+   */
+  unitLibraryUris:[uint] (id: 2);
+
+  /**
+   * List of indexes of each unit in this [PackageIndex].
+   */
+  units:[UnitIndex] (id: 4);
+
+  /**
+   * Each item of this list corresponds to the unit URI of a unique library
+   * specific unit referenced in the [PackageIndex].  It is an index into
+   * [strings] list.
+   */
+  unitUnitUris:[uint] (id: 3);
+}
+
+/**
+ * Index information about a unit in a [PackageIndex].
+ */
+table UnitIndex {
+  /**
+   * Each item of this list is the kind of an element defined in this unit.
+   */
+  definedNameKinds:[IndexNameKind] (id: 6);
+
+  /**
+   * Each item of this list is the name offset of an element defined in this
+   * unit relative to the beginning of the file.
+   */
+  definedNameOffsets:[uint] (id: 7);
+
+  /**
+   * Each item of this list corresponds to an element defined in this unit.  It
+   * is an index into [PackageIndex.strings] list.  The list is sorted in
+   * ascending order, so that the client can quickly find name definitions in
+   * this [UnitIndex].
+   */
+  definedNames:[uint] (id: 5);
+
+  /**
+   * Index into [PackageIndex.unitLibraryUris] and [PackageIndex.unitUnitUris]
+   * for the library specific unit that corresponds to this [UnitIndex].
+   */
+  unit:uint (id: 0);
+
+  /**
+   * Each item of this list is the `true` if the corresponding element usage
+   * is qualified with some prefix.
+   */
+  usedElementIsQualifiedFlags:[ubyte] (id: 11);
+
+  /**
+   * Each item of this list is the kind of the element usage.
+   */
+  usedElementKinds:[IndexRelationKind] (id: 4);
+
+  /**
+   * Each item of this list is the length of the element usage.
+   */
+  usedElementLengths:[uint] (id: 1);
+
+  /**
+   * Each item of this list is the offset of the element usage relative to the
+   * beginning of the file.
+   */
+  usedElementOffsets:[uint] (id: 2);
+
+  /**
+   * Each item of this list is the index into [PackageIndex.elementUnits] and
+   * [PackageIndex.elementOffsets].  The list is sorted in ascending order, so
+   * that the client can quickly find element references in this [UnitIndex].
+   */
+  usedElements:[uint] (id: 3);
+
+  /**
+   * Each item of this list is the kind of the name usage.
+   */
+  usedNameKinds:[IndexRelationKind] (id: 10);
+
+  /**
+   * Each item of this list is the offset of the name usage relative to the
+   * beginning of the file.
+   */
+  usedNameOffsets:[uint] (id: 9);
+
+  /**
+   * Each item of this list is the index into [PackageIndex.strings] for a
+   * used name.  The list is sorted in ascending order, so that the client can
+   * quickly find name uses in this [UnitIndex].
+   */
+  usedNames:[uint] (id: 8);
+}
+
+/**
+ * Unlinked summary information about a class declaration.
+ */
+table UnlinkedClass {
+  /**
+   * Annotations for this class.
+   */
+  annotations:[UnlinkedConst] (id: 5);
+
+  /**
+   * Documentation comment for the class, or `null` if there is no
+   * documentation comment.
+   */
+  documentationComment:UnlinkedDocumentationComment (id: 6);
+
+  /**
+   * Executable objects (methods, getters, and setters) contained in the class.
+   */
+  executables:[UnlinkedExecutable] (id: 2);
+
+  /**
+   * Field declarations contained in the class.
+   */
+  fields:[UnlinkedVariable] (id: 4);
+
+  /**
+   * Indicates whether this class is the core "Object" class (and hence has no
+   * supertype)
+   */
+  hasNoSupertype:bool (id: 12);
+
+  /**
+   * Interfaces appearing in an `implements` clause, if any.
+   */
+  interfaces:[EntityRef] (id: 7);
+
+  /**
+   * Indicates whether the class is declared with the `abstract` keyword.
+   */
+  isAbstract:bool (id: 8);
+
+  /**
+   * Indicates whether the class is declared using mixin application syntax.
+   */
+  isMixinApplication:bool (id: 11);
+
+  /**
+   * Mixins appearing in a `with` clause, if any.
+   */
+  mixins:[EntityRef] (id: 10);
+
+  /**
+   * Name of the class.
+   */
+  name:string (id: 0);
+
+  /**
+   * Offset of the class name relative to the beginning of the file.
+   */
+  nameOffset:uint (id: 1);
+
+  /**
+   * Supertype of the class, or `null` if either (a) the class doesn't
+   * explicitly declare a supertype (and hence has supertype `Object`), or (b)
+   * the class *is* `Object` (and hence has no supertype).
+   */
+  supertype:EntityRef (id: 3);
+
+  /**
+   * Type parameters of the class, if any.
+   */
+  typeParameters:[UnlinkedTypeParam] (id: 9);
+}
+
+/**
+ * Unlinked summary information about a `show` or `hide` combinator in an
+ * import or export declaration.
+ */
+table UnlinkedCombinator {
+  /**
+   * If this is a `show` combinator, offset of the end of the list of shown
+   * names.  Otherwise zero.
+   */
+  end:uint (id: 3);
+
+  /**
+   * List of names which are hidden.  Empty if this is a `show` combinator.
+   */
+  hides:[string] (id: 1);
+
+  /**
+   * If this is a `show` combinator, offset of the `show` keyword.  Otherwise
+   * zero.
+   */
+  offset:uint (id: 2);
+
+  /**
+   * List of names which are shown.  Empty if this is a `hide` combinator.
+   */
+  shows:[string] (id: 0);
+}
+
+/**
+ * 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 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 not a valid potentially constant
+   * expression.
+   */
+  isInvalid: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 {
+  /**
+   * If [kind] is `thisInvocation` or `superInvocation`, the arguments of the
+   * invocation.  Otherwise empty.
+   */
+  arguments:[UnlinkedConst] (id: 3);
+
+  /**
+   * If [kind] is `field`, the expression of the field initializer.
+   * Otherwise `null`.
+   */
+  expression:UnlinkedConst (id: 1);
+
+  /**
+   * The kind of the constructor initializer (field, redirect, super).
+   */
+  kind:UnlinkedConstructorInitializerKind (id: 2);
+
+  /**
+   * If [kind] is `field`, the name of the field declared in the class.  If
+   * [kind] is `thisInvocation`, the name of the constructor, declared in this
+   * class, to redirect to.  If [kind] is `superInvocation`, the name of the
+   * constructor, declared in the superclass, to invoke.
+   */
+  name:string (id: 0);
+}
+
+/**
+ * Unlinked summary information about a documentation comment.
+ */
+table UnlinkedDocumentationComment {
+  /**
+   * Length of the documentation comment (prior to replacing '\r\n' with '\n').
+   */
+  length:uint (id: 0);
+
+  /**
+   * Offset of the beginning of the documentation comment relative to the
+   * beginning of the file.
+   */
+  offset:uint (id: 2);
+
+  /**
+   * Text of the documentation comment, with '\r\n' replaced by '\n'.
+   *
+   * References appearing within the doc comment in square brackets are not
+   * specially encoded.
+   */
+  text:string (id: 1);
+}
+
+/**
+ * Unlinked summary information about an enum declaration.
+ */
+table UnlinkedEnum {
+  /**
+   * Annotations for this enum.
+   */
+  annotations:[UnlinkedConst] (id: 4);
+
+  /**
+   * Documentation comment for the enum, or `null` if there is no documentation
+   * comment.
+   */
+  documentationComment:UnlinkedDocumentationComment (id: 3);
+
+  /**
+   * Name of the enum type.
+   */
+  name:string (id: 0);
+
+  /**
+   * Offset of the enum name relative to the beginning of the file.
+   */
+  nameOffset:uint (id: 1);
+
+  /**
+   * Values listed in the enum declaration, in declaration order.
+   */
+  values:[UnlinkedEnumValue] (id: 2);
+}
+
+/**
+ * Unlinked summary information about a single enumerated value in an enum
+ * declaration.
+ */
+table UnlinkedEnumValue {
+  /**
+   * Documentation comment for the enum value, or `null` if there is no
+   * documentation comment.
+   */
+  documentationComment:UnlinkedDocumentationComment (id: 2);
+
+  /**
+   * Name of the enumerated value.
+   */
+  name:string (id: 0);
+
+  /**
+   * Offset of the enum value name relative to the beginning of the file.
+   */
+  nameOffset:uint (id: 1);
+}
+
+/**
+ * Unlinked summary information about a function, method, getter, or setter
+ * declaration.
+ */
+table UnlinkedExecutable {
+  /**
+   * Annotations for this executable.
+   */
+  annotations:[UnlinkedConst] (id: 6);
+
+  /**
+   * If a constant [UnlinkedExecutableKind.constructor], the constructor
+   * initializers.  Otherwise empty.
+   */
+  constantInitializers:[UnlinkedConstructorInitializer] (id: 14);
+
+  /**
+   * Documentation comment for the executable, or `null` if there is no
+   * documentation comment.
+   */
+  documentationComment:UnlinkedDocumentationComment (id: 7);
+
+  /**
+   * If this executable's return type is inferable, nonzero slot id
+   * identifying which entry in [LinkedUnit.types] contains the inferred
+   * return type.  If there is no matching entry in [LinkedUnit.types], then
+   * no return type was inferred for this variable, so its static type is
+   * `dynamic`.
+   */
+  inferredReturnTypeSlot:uint (id: 5);
+
+  /**
+   * Indicates whether the executable is declared using the `abstract` keyword.
+   */
+  isAbstract:bool (id: 10);
+
+  /**
+   * Indicates whether the executable is declared using the `const` keyword.
+   */
+  isConst:bool (id: 12);
+
+  /**
+   * Indicates whether the executable is declared using the `external` keyword.
+   */
+  isExternal:bool (id: 11);
+
+  /**
+   * Indicates whether the executable is declared using the `factory` keyword.
+   */
+  isFactory:bool (id: 8);
+
+  /**
+   * Indicates whether the executable is a redirected constructor.
+   */
+  isRedirectedConstructor:bool (id: 13);
+
+  /**
+   * Indicates whether the executable is declared using the `static` keyword.
+   *
+   * Note that for top level executables, this flag is false, since they are
+   * not declared using the `static` keyword (even though they are considered
+   * static for semantic purposes).
+   */
+  isStatic:bool (id: 9);
+
+  /**
+   * The kind of the executable (function/method, getter, setter, or
+   * constructor).
+   */
+  kind:UnlinkedExecutableKind (id: 4);
+
+  /**
+   * The list of local functions.
+   */
+  localFunctions:[UnlinkedExecutable] (id: 18);
+
+  /**
+   * The list of local labels.
+   */
+  localLabels:[UnlinkedLabel] (id: 22);
+
+  /**
+   * The list of local variables.
+   */
+  localVariables:[UnlinkedVariable] (id: 19);
+
+  /**
+   * Name of the executable.  For setters, this includes the trailing "=".  For
+   * named constructors, this excludes the class name and excludes the ".".
+   * For unnamed constructors, this is the empty string.
+   */
+  name:string (id: 1);
+
+  /**
+   * If [kind] is [UnlinkedExecutableKind.constructor] and [name] is not empty,
+   * the offset of the end of the constructor name.  Otherwise zero.
+   */
+  nameEnd:uint (id: 23);
+
+  /**
+   * Offset of the executable name relative to the beginning of the file.  For
+   * named constructors, this excludes the class name and excludes the ".".
+   * For unnamed constructors, this is the offset of the class name (i.e. the
+   * offset of the second "C" in "class C { C(); }").
+   */
+  nameOffset:uint (id: 0);
+
+  /**
+   * Parameters of the executable, if any.  Note that getters have no
+   * parameters (hence this will be the empty list), and setters have a single
+   * parameter.
+   */
+  parameters:[UnlinkedParam] (id: 2);
+
+  /**
+   * If [kind] is [UnlinkedExecutableKind.constructor] and [name] is not empty,
+   * the offset of the period before the constructor name.  Otherwise zero.
+   */
+  periodOffset:uint (id: 24);
+
+  /**
+   * If [isRedirectedConstructor] and [isFactory] are both `true`, the
+   * constructor to which this constructor redirects; otherwise empty.
+   */
+  redirectedConstructor:EntityRef (id: 15);
+
+  /**
+   * If [isRedirectedConstructor] is `true` and [isFactory] is `false`, the
+   * name of the constructor that this constructor redirects to; otherwise
+   * empty.
+   */
+  redirectedConstructorName:string (id: 17);
+
+  /**
+   * Declared return type of the executable.  Absent if the executable is a
+   * constructor or the return type is implicit.  Absent for executables
+   * associated with variable initializers and closures, since these
+   * executables may have return types that are not accessible via direct
+   * imports.
+   */
+  returnType:EntityRef (id: 3);
+
+  /**
+   * Type parameters of the executable, if any.  Empty if support for generic
+   * method syntax is disabled.
+   */
+  typeParameters:[UnlinkedTypeParam] (id: 16);
+
+  /**
+   * If a local function, the length of the visible range; zero otherwise.
+   */
+  visibleLength:uint (id: 20);
+
+  /**
+   * If a local function, the beginning of the visible range; zero otherwise.
+   */
+  visibleOffset:uint (id: 21);
+}
+
+/**
+ * Unlinked summary information about an export declaration (stored outside
+ * [UnlinkedPublicNamespace]).
+ */
+table UnlinkedExportNonPublic {
+  /**
+   * Annotations for this export directive.
+   */
+  annotations:[UnlinkedConst] (id: 3);
+
+  /**
+   * Offset of the "export" keyword.
+   */
+  offset:uint (id: 0);
+
+  /**
+   * End of the URI string (including quotes) relative to the beginning of the
+   * file.
+   */
+  uriEnd:uint (id: 1);
+
+  /**
+   * Offset of the URI string (including quotes) relative to the beginning of
+   * the file.
+   */
+  uriOffset:uint (id: 2);
+}
+
+/**
+ * Unlinked summary information about an export declaration (stored inside
+ * [UnlinkedPublicNamespace]).
+ */
+table UnlinkedExportPublic {
+  /**
+   * Combinators contained in this import declaration.
+   */
+  combinators:[UnlinkedCombinator] (id: 1);
+
+  /**
+   * URI used in the source code to reference the exported library.
+   */
+  uri:string (id: 0);
+}
+
+/**
+ * Unlinked summary information about an import declaration.
+ */
+table UnlinkedImport {
+  /**
+   * Annotations for this import declaration.
+   */
+  annotations:[UnlinkedConst] (id: 8);
+
+  /**
+   * Combinators contained in this import declaration.
+   */
+  combinators:[UnlinkedCombinator] (id: 4);
+
+  /**
+   * Indicates whether the import declaration uses the `deferred` keyword.
+   */
+  isDeferred:bool (id: 9);
+
+  /**
+   * Indicates whether the import declaration is implicit.
+   */
+  isImplicit:bool (id: 5);
+
+  /**
+   * If [isImplicit] is false, offset of the "import" keyword.  If [isImplicit]
+   * is true, zero.
+   */
+  offset:uint (id: 0);
+
+  /**
+   * Offset of the prefix name relative to the beginning of the file, or zero
+   * if there is no prefix.
+   */
+  prefixOffset:uint (id: 6);
+
+  /**
+   * Index into [UnlinkedUnit.references] of the prefix declared by this
+   * import declaration, or zero if this import declaration declares no prefix.
+   *
+   * Note that multiple imports can declare the same prefix.
+   */
+  prefixReference:uint (id: 7);
+
+  /**
+   * URI used in the source code to reference the imported library.
+   */
+  uri:string (id: 1);
+
+  /**
+   * End of the URI string (including quotes) relative to the beginning of the
+   * file.  If [isImplicit] is true, zero.
+   */
+  uriEnd:uint (id: 2);
+
+  /**
+   * Offset of the URI string (including quotes) relative to the beginning of
+   * the file.  If [isImplicit] is true, zero.
+   */
+  uriOffset:uint (id: 3);
+}
+
+/**
+ * Unlinked summary information about a label.
+ */
+table UnlinkedLabel {
+  /**
+   * Return `true` if this label is associated with a `switch` member (`case` or
+   * `default`).
+   */
+  isOnSwitchMember:bool (id: 2);
+
+  /**
+   * Return `true` if this label is associated with a `switch` statement.
+   */
+  isOnSwitchStatement:bool (id: 3);
+
+  /**
+   * Name of the label.
+   */
+  name:string (id: 0);
+
+  /**
+   * Offset of the label relative to the beginning of the file.
+   */
+  nameOffset:uint (id: 1);
+}
+
+/**
+ * Unlinked summary information about a function parameter.
+ */
+table UnlinkedParam {
+  /**
+   * Annotations for this parameter.
+   */
+  annotations:[UnlinkedConst] (id: 9);
+
+  /**
+   * If the parameter has a default value, the constant expression in the
+   * default value.  Note that the presence of this expression does not mean
+   * that it is a valid, check [UnlinkedConst.isInvalid].
+   */
+  defaultValue:UnlinkedConst (id: 7);
+
+  /**
+   * If the parameter has a default value, the source text of the constant
+   * expression in the default value.  Otherwise the empty string.
+   */
+  defaultValueCode:string (id: 13);
+
+  /**
+   * If this parameter's type is inferable, nonzero slot id identifying which
+   * entry in [LinkedLibrary.types] contains the inferred type.  If there is no
+   * matching entry in [LinkedLibrary.types], then no type was inferred for
+   * this variable, so its static type is `dynamic`.
+   *
+   * Note that although strong mode considers initializing formals to be
+   * inferable, they are not marked as such in the summary; if their type is
+   * not specified, they always inherit the static type of the corresponding
+   * field.
+   */
+  inferredTypeSlot:uint (id: 2);
+
+  /**
+   * The synthetic initializer function of the parameter.  Absent if the variable
+   * does not have an initializer.
+   */
+  initializer:UnlinkedExecutable (id: 12);
+
+  /**
+   * Indicates whether this is a function-typed parameter.
+   */
+  isFunctionTyped:bool (id: 5);
+
+  /**
+   * Indicates whether this is an initializing formal parameter (i.e. it is
+   * declared using `this.` syntax).
+   */
+  isInitializingFormal:bool (id: 6);
+
+  /**
+   * Kind of the parameter.
+   */
+  kind:UnlinkedParamKind (id: 4);
+
+  /**
+   * Name of the parameter.
+   */
+  name:string (id: 0);
+
+  /**
+   * Offset of the parameter name relative to the beginning of the file.
+   */
+  nameOffset:uint (id: 1);
+
+  /**
+   * If [isFunctionTyped] is `true`, the parameters of the function type.
+   */
+  parameters:[UnlinkedParam] (id: 8);
+
+  /**
+   * If [isFunctionTyped] is `true`, the declared return type.  If
+   * [isFunctionTyped] is `false`, the declared type.  Absent if the type is
+   * implicit.
+   */
+  type:EntityRef (id: 3);
+
+  /**
+   * The length of the visible range.
+   */
+  visibleLength:uint (id: 10);
+
+  /**
+   * The beginning of the visible range.
+   */
+  visibleOffset:uint (id: 11);
+}
+
+/**
+ * Unlinked summary information about a part declaration.
+ */
+table UnlinkedPart {
+  /**
+   * Annotations for this part declaration.
+   */
+  annotations:[UnlinkedConst] (id: 2);
+
+  /**
+   * End of the URI string (including quotes) relative to the beginning of the
+   * file.
+   */
+  uriEnd:uint (id: 0);
+
+  /**
+   * Offset of the URI string (including quotes) relative to the beginning of
+   * the file.
+   */
+  uriOffset:uint (id: 1);
+}
+
+/**
+ * Unlinked summary information about a specific name contributed by a
+ * compilation unit to a library's public namespace.
+ *
+ * TODO(paulberry): some of this information is redundant with information
+ * elsewhere in the summary.  Consider reducing the redundancy to reduce
+ * summary size.
+ */
+table UnlinkedPublicName {
+  /**
+   * The kind of object referred to by the name.
+   */
+  kind:ReferenceKind (id: 1);
+
+  /**
+   * If this [UnlinkedPublicName] is a class, the list of members which can be
+   * referenced from constants or factory redirects - static constant fields,
+   * static methods, and constructors.  Otherwise empty.
+   *
+   * Unnamed constructors are not included since they do not constitute a
+   * separate name added to any namespace.
+   */
+  members:[UnlinkedPublicName] (id: 2);
+
+  /**
+   * The name itself.
+   */
+  name:string (id: 0);
+
+  /**
+   * If the entity being referred to is generic, the number of type parameters
+   * it accepts.  Otherwise zero.
+   */
+  numTypeParameters:uint (id: 3);
+}
+
+/**
+ * Unlinked summary information about what a compilation unit contributes to a
+ * library's public namespace.  This is the subset of [UnlinkedUnit] that is
+ * required from dependent libraries in order to perform prelinking.
+ */
+table UnlinkedPublicNamespace {
+  /**
+   * Export declarations in the compilation unit.
+   */
+  exports:[UnlinkedExportPublic] (id: 2);
+
+  /**
+   * Public names defined in the compilation unit.
+   *
+   * TODO(paulberry): consider sorting these names to reduce unnecessary
+   * relinking.
+   */
+  names:[UnlinkedPublicName] (id: 0);
+
+  /**
+   * URIs referenced by part declarations in the compilation unit.
+   */
+  parts:[string] (id: 1);
+}
+
+/**
+ * Unlinked summary information about a name referred to in one library that
+ * might be defined in another.
+ */
+table UnlinkedReference {
+  /**
+   * Name of the entity being referred to.  For the pseudo-type `dynamic`, the
+   * string is "dynamic".  For the pseudo-type `void`, the string is "void".
+   * For the pseudo-type `bottom`, the string is "*bottom*".
+   */
+  name:string (id: 0);
+
+  /**
+   * Prefix used to refer to the entity, or zero if no prefix is used.  This is
+   * an index into [UnlinkedUnit.references].
+   *
+   * Prefix references must always point backward; that is, for all i, if
+   * UnlinkedUnit.references[i].prefixReference != 0, then
+   * UnlinkedUnit.references[i].prefixReference < i.
+   */
+  prefixReference:uint (id: 1);
+}
+
+/**
+ * Unlinked summary information about a typedef declaration.
+ */
+table UnlinkedTypedef {
+  /**
+   * Annotations for this typedef.
+   */
+  annotations:[UnlinkedConst] (id: 4);
+
+  /**
+   * Documentation comment for the typedef, or `null` if there is no
+   * documentation comment.
+   */
+  documentationComment:UnlinkedDocumentationComment (id: 6);
+
+  /**
+   * Name of the typedef.
+   */
+  name:string (id: 0);
+
+  /**
+   * Offset of the typedef name relative to the beginning of the file.
+   */
+  nameOffset:uint (id: 1);
+
+  /**
+   * Parameters of the executable, if any.
+   */
+  parameters:[UnlinkedParam] (id: 3);
+
+  /**
+   * Return type of the typedef.
+   */
+  returnType:EntityRef (id: 2);
+
+  /**
+   * Type parameters of the typedef, if any.
+   */
+  typeParameters:[UnlinkedTypeParam] (id: 5);
+}
+
+/**
+ * Unlinked summary information about a type parameter declaration.
+ */
+table UnlinkedTypeParam {
+  /**
+   * Annotations for this type parameter.
+   */
+  annotations:[UnlinkedConst] (id: 3);
+
+  /**
+   * Bound of the type parameter, if a bound is explicitly declared.  Otherwise
+   * null.
+   */
+  bound:EntityRef (id: 2);
+
+  /**
+   * Name of the type parameter.
+   */
+  name:string (id: 0);
+
+  /**
+   * Offset of the type parameter name relative to the beginning of the file.
+   */
+  nameOffset:uint (id: 1);
+}
+
+/**
+ * Unlinked summary information about a compilation unit ("part file").
+ */
+table UnlinkedUnit {
+  /**
+   * Classes declared in the compilation unit.
+   */
+  classes:[UnlinkedClass] (id: 2);
+
+  /**
+   * Enums declared in the compilation unit.
+   */
+  enums:[UnlinkedEnum] (id: 12);
+
+  /**
+   * Top level executable objects (functions, getters, and setters) declared in
+   * the compilation unit.
+   */
+  executables:[UnlinkedExecutable] (id: 4);
+
+  /**
+   * Export declarations in the compilation unit.
+   */
+  exports:[UnlinkedExportNonPublic] (id: 13);
+
+  /**
+   * Import declarations in the compilation unit.
+   */
+  imports:[UnlinkedImport] (id: 5);
+
+  /**
+   * Annotations for the library declaration, or the empty list if there is no
+   * library declaration.
+   */
+  libraryAnnotations:[UnlinkedConst] (id: 14);
+
+  /**
+   * Documentation comment for the library, or `null` if there is no
+   * documentation comment.
+   */
+  libraryDocumentationComment:UnlinkedDocumentationComment (id: 9);
+
+  /**
+   * Name of the library (from a "library" declaration, if present).
+   */
+  libraryName:string (id: 6);
+
+  /**
+   * Length of the library name as it appears in the source code (or 0 if the
+   * library has no name).
+   */
+  libraryNameLength:uint (id: 7);
+
+  /**
+   * Offset of the library name relative to the beginning of the file (or 0 if
+   * the library has no name).
+   */
+  libraryNameOffset:uint (id: 8);
+
+  /**
+   * Part declarations in the compilation unit.
+   */
+  parts:[UnlinkedPart] (id: 11);
+
+  /**
+   * Unlinked public namespace of this compilation unit.
+   */
+  publicNamespace:UnlinkedPublicNamespace (id: 0);
+
+  /**
+   * Top level and prefixed names referred to by this compilation unit.  The
+   * zeroth element of this array is always populated and is used to represent
+   * the absence of a reference in places where a reference is optional (for
+   * example [UnlinkedReference.prefixReference or
+   * UnlinkedImport.prefixReference]).
+   */
+  references:[UnlinkedReference] (id: 1);
+
+  /**
+   * Typedefs declared in the compilation unit.
+   */
+  typedefs:[UnlinkedTypedef] (id: 10);
+
+  /**
+   * Top level variables declared in the compilation unit.
+   */
+  variables:[UnlinkedVariable] (id: 3);
+}
+
+/**
+ * Unlinked summary information about a top level variable, local variable, or
+ * a field.
+ */
+table UnlinkedVariable {
+  /**
+   * Annotations for this variable.
+   */
+  annotations:[UnlinkedConst] (id: 8);
+
+  /**
+   * If [isConst] is true, and the variable has an initializer, the constant
+   * expression in the initializer.  Note that the presence of this expression
+   * does not mean that it is a valid, check [UnlinkedConst.isInvalid].
+   */
+  constExpr:UnlinkedConst (id: 5);
+
+  /**
+   * Documentation comment for the variable, or `null` if there is no
+   * documentation comment.
+   */
+  documentationComment:UnlinkedDocumentationComment (id: 10);
+
+  /**
+   * If this variable is inferable, nonzero slot id identifying which entry in
+   * [LinkedLibrary.types] contains the inferred type for this variable.  If
+   * there is no matching entry in [LinkedLibrary.types], then no type was
+   * inferred for this variable, so its static type is `dynamic`.
+   */
+  inferredTypeSlot:uint (id: 9);
+
+  /**
+   * The synthetic initializer function of the variable.  Absent if the variable
+   * does not have an initializer.
+   */
+  initializer:UnlinkedExecutable (id: 13);
+
+  /**
+   * Indicates whether the variable is declared using the `const` keyword.
+   */
+  isConst:bool (id: 6);
+
+  /**
+   * Indicates whether the variable is declared using the `final` keyword.
+   */
+  isFinal:bool (id: 7);
+
+  /**
+   * Indicates whether the variable is declared using the `static` keyword.
+   *
+   * Note that for top level variables, this flag is false, since they are not
+   * declared using the `static` keyword (even though they are considered
+   * static for semantic purposes).
+   */
+  isStatic:bool (id: 4);
+
+  /**
+   * Name of the variable.
+   */
+  name:string (id: 0);
+
+  /**
+   * Offset of the variable name relative to the beginning of the file.
+   */
+  nameOffset:uint (id: 1);
+
+  /**
+   * If this variable is propagable, nonzero slot id identifying which entry in
+   * [LinkedLibrary.types] contains the propagated type for this variable.  If
+   * there is no matching entry in [LinkedLibrary.types], then this variable's
+   * propagated type is the same as its declared type.
+   *
+   * Non-propagable variables have a [propagatedTypeSlot] of zero.
+   */
+  propagatedTypeSlot:uint (id: 2);
+
+  /**
+   * Declared type of the variable.  Absent if the type is implicit.
+   */
+  type:EntityRef (id: 3);
+
+  /**
+   * If a local variable, the length of the visible range; zero otherwise.
+   */
+  visibleLength:uint (id: 11);
+
+  /**
+   * If a local variable, the beginning of the visible range; zero otherwise.
+   */
+  visibleOffset:uint (id: 12);
+}
+
+root_type PackageBundle;
+
+file_identifier "PBdl";
diff --git a/pkg/analyzer/lib/src/summary/idl.dart b/pkg/analyzer/lib/src/summary/idl.dart
index 9d840b9..21473a2 100644
--- a/pkg/analyzer/lib/src/summary/idl.dart
+++ b/pkg/analyzer/lib/src/summary/idl.dart
@@ -42,7 +42,7 @@
 library analyzer.tool.summary.idl;
 
 import 'base.dart' as base;
-import 'base.dart' show Id;
+import 'base.dart' show Id, TopLevel;
 import 'format.dart' as generated;
 
 /**
@@ -53,12 +53,6 @@
 const informative = null;
 
 /**
- * Annotation describing a class which can be the top level object in an
- * encoded summary.
- */
-const topLevel = null;
-
-/**
  * Summary information about a reference to a an entity such as a type, top
  * level executable, or executable within a class.
  */
@@ -128,6 +122,24 @@
   int get slot;
 
   /**
+   * If this [EntityRef] is a reference to a function type whose
+   * [FunctionElement] is not in any library (e.g. a function type that was
+   * synthesized by a LUB computation), the function parameters.  Otherwise
+   * empty.
+   */
+  @Id(6)
+  List<UnlinkedParam> get syntheticParams;
+
+  /**
+   * If this [EntityRef] is a reference to a function type whose
+   * [FunctionElement] is not in any library (e.g. a function type that was
+   * synthesized by a LUB computation), the return type of the function.
+   * Otherwise `null`.
+   */
+  @Id(5)
+  EntityRef get syntheticReturnType;
+
+  /**
    * If this is an instantiation of a generic type or generic executable, the
    * type arguments used to instantiate it.  Trailing type arguments of type
    * `dynamic` are omitted.
@@ -137,6 +149,88 @@
 }
 
 /**
+ * Enum used to indicate the kind of a name in index.
+ */
+enum IndexNameKind {
+  /**
+   * A top-level element.
+   */
+  topLevel,
+
+  /**
+   * A class member.
+   */
+  classMember
+}
+
+/**
+ * Enum used to indicate the kind of an index relation.
+ */
+enum IndexRelationKind {
+  /**
+   * Left: class.
+   *   Is extended by.
+   * Right: other class declaration.
+   */
+  IS_EXTENDED_BY,
+
+  /**
+   * Left: class.
+   *   Is implemented by.
+   * Right: other class declaration.
+   */
+  IS_IMPLEMENTED_BY,
+
+  /**
+   * Left: class.
+   *   Is mixed into.
+   * Right: other class declaration.
+   */
+  IS_MIXED_IN_BY,
+
+  /**
+   * Left: method, property accessor, function, variable.
+   *   Is invoked at.
+   * Right: location.
+   */
+  IS_INVOKED_BY,
+
+  /**
+   * Left: any element.
+   *   Is referenced (and not invoked, read/written) at.
+   * Right: location.
+   */
+  IS_REFERENCED_BY
+}
+
+/**
+ * When we need to reference a synthetic element in [PackageIndex] we use a
+ * value of this enum to specify which kind of the synthetic element we
+ * actually reference.
+ */
+enum IndexSyntheticElementKind {
+  /**
+   * Not a synthetic element.
+   */
+  notSynthetic,
+
+  /**
+   * The unnamed synthetic constructor a class element.
+   */
+  constructor,
+
+  /**
+   * The synthetic getter of a property introducing element.
+   */
+  getter,
+
+  /**
+   * The synthetic setter of a property introducing element.
+   */
+  setter
+}
+
+/**
  * Information about a dependency that exists between one library and another
  * due to an "import" declaration.
  */
@@ -197,7 +291,7 @@
 /**
  * Linked summary of a library.
  */
-@topLevel
+@TopLevel('LLib')
 abstract class LinkedLibrary extends base.SummaryClass {
   factory LinkedLibrary.fromBuffer(List<int> buffer) =>
       generated.readLinkedLibrary(buffer);
@@ -356,7 +450,7 @@
 /**
  * Summary information about a package.
  */
-@topLevel
+@TopLevel('PBdl')
 abstract class PackageBundle extends base.SummaryClass {
   factory PackageBundle.fromBuffer(List<int> buffer) =>
       generated.readPackageBundle(buffer);
@@ -375,6 +469,20 @@
   List<String> get linkedLibraryUris;
 
   /**
+   * Major version of the summary format.  See
+   * [PackageBundleAssembler.currentMajorVersion].
+   */
+  @Id(5)
+  int get majorVersion;
+
+  /**
+   * Minor version of the summary format.  See
+   * [PackageBundleAssembler.currentMinorVersion].
+   */
+  @Id(6)
+  int get minorVersion;
+
+  /**
    * List of MD5 hashes of the files listed in [unlinkedUnitUris].  Each hash
    * is encoded as a hexadecimal string using lower case letters.
    */
@@ -395,6 +503,67 @@
 }
 
 /**
+ * Index information about a package.
+ */
+@TopLevel('Indx')
+abstract class PackageIndex extends base.SummaryClass {
+  factory PackageIndex.fromBuffer(List<int> buffer) =>
+      generated.readPackageIndex(buffer);
+
+  /**
+   * Each item of this list corresponds to a unique referenced element.  It is
+   * the kind of the synthetic element.
+   */
+  @Id(5)
+  List<IndexSyntheticElementKind> get elementKinds;
+
+  /**
+   * Each item of this list corresponds to a unique referenced element.  It is
+   * the offset of the element name relative to the beginning of the file.  The
+   * list is sorted in ascending order, so that the client can quickly check
+   * whether an element is referenced in this [PackageIndex].
+   */
+  @Id(1)
+  List<int> get elementOffsets;
+
+  /**
+   * Each item of this list corresponds to a unique referenced element.  It is
+   * the index into [unitLibraryUris] and [unitUnitUris] for the library
+   * specific unit where the element is declared.
+   */
+  @Id(0)
+  List<int> get elementUnits;
+
+  /**
+   * List of unique element strings used in this [PackageIndex].
+   */
+  @Id(6)
+  List<String> get strings;
+
+  /**
+   * Each item of this list corresponds to the library URI of a unique library
+   * specific unit referenced in the [PackageIndex].  It is an index into
+   * [strings] list.
+   */
+  @Id(2)
+  List<int> get unitLibraryUris;
+
+  /**
+   * List of indexes of each unit in this [PackageIndex].
+   */
+  @Id(4)
+  List<UnitIndex> get units;
+
+  /**
+   * Each item of this list corresponds to the unit URI of a unique library
+   * specific unit referenced in the [PackageIndex].  It is an index into
+   * [strings] list.
+   */
+  @Id(3)
+  List<int> get unitUnitUris;
+}
+
+/**
  * Enum used to indicate the kind of entity referred to by a
  * [LinkedReference].
  */
@@ -463,6 +632,95 @@
 }
 
 /**
+ * Index information about a unit in a [PackageIndex].
+ */
+abstract class UnitIndex extends base.SummaryClass {
+  /**
+   * Each item of this list is the kind of an element defined in this unit.
+   */
+  @Id(6)
+  List<IndexNameKind> get definedNameKinds;
+
+  /**
+   * Each item of this list is the name offset of an element defined in this
+   * unit relative to the beginning of the file.
+   */
+  @Id(7)
+  List<int> get definedNameOffsets;
+
+  /**
+   * Each item of this list corresponds to an element defined in this unit.  It
+   * is an index into [PackageIndex.strings] list.  The list is sorted in
+   * ascending order, so that the client can quickly find name definitions in
+   * this [UnitIndex].
+   */
+  @Id(5)
+  List<int> get definedNames;
+
+  /**
+   * Index into [PackageIndex.unitLibraryUris] and [PackageIndex.unitUnitUris]
+   * for the library specific unit that corresponds to this [UnitIndex].
+   */
+  @Id(0)
+  int get unit;
+
+  /**
+   * Each item of this list is the `true` if the corresponding element usage
+   * is qualified with some prefix.
+   */
+  @Id(11)
+  List<bool> get usedElementIsQualifiedFlags;
+
+  /**
+   * Each item of this list is the kind of the element usage.
+   */
+  @Id(4)
+  List<IndexRelationKind> get usedElementKinds;
+
+  /**
+   * Each item of this list is the length of the element usage.
+   */
+  @Id(1)
+  List<int> get usedElementLengths;
+
+  /**
+   * Each item of this list is the offset of the element usage relative to the
+   * beginning of the file.
+   */
+  @Id(2)
+  List<int> get usedElementOffsets;
+
+  /**
+   * Each item of this list is the index into [PackageIndex.elementUnits] and
+   * [PackageIndex.elementOffsets].  The list is sorted in ascending order, so
+   * that the client can quickly find element references in this [UnitIndex].
+   */
+  @Id(3)
+  List<int> get usedElements;
+
+  /**
+   * Each item of this list is the kind of the name usage.
+   */
+  @Id(10)
+  List<IndexRelationKind> get usedNameKinds;
+
+  /**
+   * Each item of this list is the offset of the name usage relative to the
+   * beginning of the file.
+   */
+  @Id(9)
+  List<int> get usedNameOffsets;
+
+  /**
+   * Each item of this list is the index into [PackageIndex.strings] for a
+   * used name.  The list is sorted in ascending order, so that the client can
+   * quickly find name uses in this [UnitIndex].
+   */
+  @Id(8)
+  List<int> get usedNames;
+}
+
+/**
  * Unlinked summary information about a class declaration.
  */
 abstract class UnlinkedClass extends base.SummaryClass {
@@ -1648,7 +1906,7 @@
  * library's public namespace.  This is the subset of [UnlinkedUnit] that is
  * required from dependent libraries in order to perform prelinking.
  */
-@topLevel
+@TopLevel('UPNS')
 abstract class UnlinkedPublicNamespace extends base.SummaryClass {
   factory UnlinkedPublicNamespace.fromBuffer(List<int> buffer) =>
       generated.readUnlinkedPublicNamespace(buffer);
@@ -1784,7 +2042,7 @@
 /**
  * Unlinked summary information about a compilation unit ("part file").
  */
-@topLevel
+@TopLevel('UUnt')
 abstract class UnlinkedUnit extends base.SummaryClass {
   factory UnlinkedUnit.fromBuffer(List<int> buffer) =>
       generated.readUnlinkedUnit(buffer);
diff --git a/pkg/analyzer/lib/src/summary/index_unit.dart b/pkg/analyzer/lib/src/summary/index_unit.dart
new file mode 100644
index 0000000..db659c7
--- /dev/null
+++ b/pkg/analyzer/lib/src/summary/index_unit.dart
@@ -0,0 +1,676 @@
+// 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/token.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/member.dart';
+import 'package:analyzer/src/generated/utilities_dart.dart';
+import 'package:analyzer/src/summary/format.dart';
+import 'package:analyzer/src/summary/idl.dart';
+
+/**
+ * Object that gathers information about the whole package index and then uses
+ * it to assemble a new [PackageIndexBuilder].  Call [index] on each compilation
+ * unit to be indexed, then call [assemble] to retrieve the complete index for
+ * the package.
+ */
+class PackageIndexAssembler {
+  /**
+   * Map associating referenced elements with their [_ElementInfo]s.
+   */
+  final Map<Element, _ElementInfo> _elementMap = <Element, _ElementInfo>{};
+
+  /**
+   * Map associating [CompilationUnitElement]s with their identifiers, which
+   * are indices into [_unitLibraryUris] and [_unitUnitUris].
+   */
+  final Map<CompilationUnitElement, int> _unitMap =
+      <CompilationUnitElement, int>{};
+
+  /**
+   * Each item of this list corresponds to the library URI of a unique
+   * [CompilationUnitElement].  It is an index into [_strings].
+   */
+  final List<int> _unitLibraryUris = <int>[];
+
+  /**
+   * Each item of this list corresponds to the unit URI of a unique
+   * [CompilationUnitElement].  It is an index into [_strings].
+   */
+  final List<int> _unitUnitUris = <int>[];
+
+  /**
+   * Map associating strings with their identifiers, which are indices
+   * into [_strings].
+   */
+  final Map<String, int> _stringMap = <String, int>{};
+
+  /**
+   * List of unique strings used in this index.
+   */
+  final List<String> _strings = <String>[];
+
+  /**
+   * List of information about each unit indexed in this index.
+   */
+  final List<_UnitIndexAssembler> _units = <_UnitIndexAssembler>[];
+
+  /**
+   * Assemble a new [PackageIndexBuilder] using the information gathered by
+   * [index].
+   */
+  PackageIndexBuilder assemble() {
+    List<_ElementInfo> elementInfoList = _elementMap.values.toList();
+    elementInfoList.sort((a, b) {
+      return a.offset - b.offset;
+    });
+    for (int i = 0; i < elementInfoList.length; i++) {
+      elementInfoList[i].id = i;
+    }
+    return new PackageIndexBuilder(
+        unitLibraryUris: _unitLibraryUris,
+        unitUnitUris: _unitUnitUris,
+        elementUnits: elementInfoList.map((e) => e.unitId).toList(),
+        elementOffsets: elementInfoList.map((e) => e.offset).toList(),
+        elementKinds: elementInfoList.map((e) => e.kind).toList(),
+        strings: _strings,
+        units: _units.map((unit) => unit.assemble()).toList());
+  }
+
+  /**
+   * Index the given fully resolved [unit].
+   */
+  void index(CompilationUnit unit) {
+    int unitId = _getUnitId(unit.element);
+    _UnitIndexAssembler assembler = new _UnitIndexAssembler(this, unitId);
+    _units.add(assembler);
+    unit.accept(new _IndexContributor(assembler));
+  }
+
+  /**
+   * Return the unique [_ElementInfo] corresponding the [element].  The field
+   * [_ElementInfo.id] is filled by [assemble] during final sorting.
+   */
+  _ElementInfo _getElementInfo(Element element) {
+    if (element is Member) {
+      element = (element as Member).baseElement;
+    }
+    return _elementMap.putIfAbsent(element, () {
+      CompilationUnitElement unitElement = getUnitElement(element);
+      int unitId = _getUnitId(unitElement);
+      int offset = element.nameOffset;
+      if (element is LibraryElement || element is CompilationUnitElement) {
+        offset = 0;
+      }
+      IndexSyntheticElementKind kind = getIndexElementKind(element);
+      return new _ElementInfo(unitId, offset, kind);
+    });
+  }
+
+  /**
+   * Add information about [str] to [_strings] if necessary, and return the
+   * location in this array representing [str].
+   */
+  int _getStringId(String str) {
+    return _stringMap.putIfAbsent(str, () {
+      int id = _strings.length;
+      _strings.add(str);
+      return id;
+    });
+  }
+
+  /**
+   * Add information about [unitElement] to [_unitUnitUris] and
+   * [_unitLibraryUris] if necessary, and return the location in those
+   * arrays representing [unitElement].
+   */
+  int _getUnitId(CompilationUnitElement unitElement) {
+    return _unitMap.putIfAbsent(unitElement, () {
+      assert(_unitLibraryUris.length == _unitUnitUris.length);
+      int id = _unitUnitUris.length;
+      _unitLibraryUris.add(_getUriId(unitElement.library.source.uri));
+      _unitUnitUris.add(_getUriId(unitElement.source.uri));
+      return id;
+    });
+  }
+
+  /**
+   * Return the identifier corresponding to [uri].
+   */
+  int _getUriId(Uri uri) {
+    String str = uri.toString();
+    return _getStringId(str);
+  }
+
+  /**
+   * Return the kind of the given [element].
+   */
+  static IndexSyntheticElementKind getIndexElementKind(Element element) {
+    if (element.isSynthetic) {
+      if (element is ConstructorElement) {
+        return IndexSyntheticElementKind.constructor;
+      }
+      if (element is PropertyAccessorElement) {
+        return element.isGetter
+            ? IndexSyntheticElementKind.getter
+            : IndexSyntheticElementKind.setter;
+      }
+    }
+    return IndexSyntheticElementKind.notSynthetic;
+  }
+
+  /**
+   * Return the [CompilationUnitElement] that should be used for [element].
+   * Throw [StateError] if the [element] is not linked into a unit.
+   */
+  static CompilationUnitElement getUnitElement(Element element) {
+    for (Element e = element; e != null; e = e.enclosingElement) {
+      if (e is CompilationUnitElement) {
+        return e;
+      }
+      if (e is LibraryElement) {
+        return e.definingCompilationUnit;
+      }
+    }
+    throw new StateError(element.toString());
+  }
+}
+
+/**
+ * Information about a single defined name.  Any [_DefinedNameInfo] is always
+ * part of a [_UnitIndexAssembler], so [offset] should be understood within the
+ * context of the compilation unit pointed to by the [_UnitIndexAssembler].
+ */
+class _DefinedNameInfo {
+  /**
+   * The identifier of the name returned [PackageIndexAssembler._getStringId].
+   */
+  final int nameId;
+
+  /**
+   * The coarse-grained kind of the defined name.
+   */
+  final IndexNameKind kind;
+
+  /**
+   * The name offset of the defined element.
+   */
+  final int offset;
+
+  _DefinedNameInfo(this.nameId, this.kind, this.offset);
+}
+
+/**
+ * Information about an element referenced in index.
+ */
+class _ElementInfo {
+  /**
+   * The identifier of the [CompilationUnitElement] containing this element.
+   */
+  final int unitId;
+
+  /**
+   * The name offset of the element.
+   */
+  final int offset;
+
+  /**
+   * The kind of the element.
+   */
+  final IndexSyntheticElementKind kind;
+
+  /**
+   * The unique id of the element.  It is set after indexing of the whole
+   * package is done and we are assembling the full package index.
+   */
+  int id;
+
+  _ElementInfo(this.unitId, this.offset, this.kind);
+}
+
+/**
+ * Information about a single relation.  Any [_ElementRelationInfo] is always
+ * part of a [_UnitIndexAssembler], so [offset] and [length] should be
+ * understood within the context of the compilation unit pointed to by the
+ * [_UnitIndexAssembler].
+ */
+class _ElementRelationInfo {
+  final _ElementInfo elementInfo;
+  final IndexRelationKind kind;
+  final int offset;
+  final int length;
+  final bool isQualified;
+
+  _ElementRelationInfo(
+      this.elementInfo, this.kind, this.offset, this.length, this.isQualified);
+}
+
+/**
+ * Visits a resolved AST and adds relationships into [_UnitIndexAssembler].
+ */
+class _IndexContributor extends GeneralizingAstVisitor {
+  final _UnitIndexAssembler assembler;
+
+  _IndexContributor(this.assembler);
+
+  /**
+   * Record definition of the given [element].
+   */
+  void recordDefinedElement(Element element) {
+    if (element != null) {
+      String name = element.displayName;
+      int offset = element.nameOffset;
+      Element enclosing = element.enclosingElement;
+      if (enclosing is CompilationUnitElement) {
+        assembler.defineName(name, IndexNameKind.topLevel, offset);
+      } else if (enclosing is ClassElement) {
+        assembler.defineName(name, IndexNameKind.classMember, offset);
+      }
+    }
+  }
+
+  /**
+   * Record that the name [node] has a relation of the given [kind].
+   */
+  void recordNameRelation(SimpleIdentifier node, IndexRelationKind kind) {
+    if (node != null) {
+      assembler.addNameRelation(node.name, kind, node.offset);
+    }
+  }
+
+  /**
+   * Record reference to the given operator [Element].
+   */
+  void recordOperatorReference(Token operator, Element element) {
+    recordRelationToken(element, IndexRelationKind.IS_INVOKED_BY, operator);
+  }
+
+  /**
+   * Record that [element] has a relation of the given [kind] at the location
+   * of the given [node].  The flag [isQualified] is `true` if [node] has an
+   * explicit or implicit qualifier, so cannot be shadowed by a local
+   * declaration.
+   */
+  void recordRelation(
+      Element element, IndexRelationKind kind, AstNode node, bool isQualified) {
+    if (element != null && node != null) {
+      recordRelationOffset(
+          element, kind, node.offset, node.length, isQualified);
+    }
+  }
+
+  /**
+   * Record that [element] has a relation of the given [kind] at the given
+   * [offset] and [length].  The flag [isQualified] is `true` if the relation
+   * has an explicit or implicit qualifier, so [element] cannot be shadowed by
+   * a local declaration.
+   */
+  void recordRelationOffset(Element element, IndexRelationKind kind, int offset,
+      int length, bool isQualified) {
+    // Ignore elements that can't be referenced outside of the unit.
+    if (element == null ||
+        element is FunctionElement &&
+            element.enclosingElement is ExecutableElement ||
+        element is LabelElement ||
+        element is LocalVariableElement ||
+        element is ParameterElement &&
+            element.parameterKind != ParameterKind.NAMED ||
+        element is PrefixElement ||
+        element is TypeParameterElement) {
+      return;
+    }
+    // Add the relation.
+    assembler.addElementRelation(element, kind, offset, length, isQualified);
+  }
+
+  /**
+   * Record that [element] has a relation of the given [kind] at the location
+   * of the given [token].
+   */
+  void recordRelationToken(
+      Element element, IndexRelationKind kind, Token token) {
+    if (element != null && token != null) {
+      recordRelationOffset(element, kind, token.offset, token.length, true);
+    }
+  }
+
+  /**
+   * Record a relation between a super [typeName] and its [Element].
+   */
+  void recordSuperType(TypeName typeName, IndexRelationKind kind) {
+    Identifier name = typeName?.name;
+    if (name != null) {
+      Element element = name.staticElement;
+      SimpleIdentifier relNode =
+          name is PrefixedIdentifier ? name.identifier : name;
+      recordRelation(element, kind, relNode, true);
+      recordRelation(
+          element, IndexRelationKind.IS_REFERENCED_BY, relNode, true);
+      typeName.typeArguments?.accept(this);
+    }
+  }
+
+  void recordUriReference(Element element, UriBasedDirective directive) {
+    recordRelation(
+        element, IndexRelationKind.IS_REFERENCED_BY, directive.uri, true);
+  }
+
+  @override
+  visitAssignmentExpression(AssignmentExpression node) {
+    recordOperatorReference(node.operator, node.bestElement);
+    super.visitAssignmentExpression(node);
+  }
+
+  @override
+  visitBinaryExpression(BinaryExpression node) {
+    recordOperatorReference(node.operator, node.bestElement);
+    super.visitBinaryExpression(node);
+  }
+
+  @override
+  visitClassDeclaration(ClassDeclaration node) {
+    if (node.extendsClause == null) {
+      ClassElement objectElement = node.element.supertype?.element;
+      recordRelationOffset(objectElement, IndexRelationKind.IS_EXTENDED_BY,
+          node.name.offset, 0, true);
+    }
+    super.visitClassDeclaration(node);
+  }
+
+  @override
+  visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
+    SimpleIdentifier fieldName = node.fieldName;
+    if (fieldName != null) {
+      Element element = fieldName.staticElement;
+      recordRelation(
+          element, IndexRelationKind.IS_REFERENCED_BY, fieldName, true);
+    }
+    node.expression?.accept(this);
+  }
+
+  @override
+  visitConstructorName(ConstructorName node) {
+    ConstructorElement element = node.staticElement;
+    element = _getActualConstructorElement(element);
+    // record relation
+    if (node.name != null) {
+      int offset = node.period.offset;
+      int length = node.name.end - offset;
+      recordRelationOffset(
+          element, IndexRelationKind.IS_REFERENCED_BY, offset, length, true);
+    } else {
+      int offset = node.type.end;
+      recordRelationOffset(
+          element, IndexRelationKind.IS_REFERENCED_BY, offset, 0, true);
+    }
+    super.visitConstructorName(node);
+  }
+
+  @override
+  visitExportDirective(ExportDirective node) {
+    ExportElement element = node.element;
+    recordUriReference(element?.exportedLibrary, node);
+    super.visitExportDirective(node);
+  }
+
+  @override
+  visitExtendsClause(ExtendsClause node) {
+    recordSuperType(node.superclass, IndexRelationKind.IS_EXTENDED_BY);
+  }
+
+  @override
+  visitImplementsClause(ImplementsClause node) {
+    for (TypeName typeName in node.interfaces) {
+      recordSuperType(typeName, IndexRelationKind.IS_IMPLEMENTED_BY);
+    }
+  }
+
+  @override
+  visitImportDirective(ImportDirective node) {
+    ImportElement element = node.element;
+    recordUriReference(element?.importedLibrary, node);
+    super.visitImportDirective(node);
+  }
+
+  @override
+  visitIndexExpression(IndexExpression node) {
+    MethodElement element = node.bestElement;
+    if (element is MethodElement) {
+      Token operator = node.leftBracket;
+      recordRelationToken(element, IndexRelationKind.IS_INVOKED_BY, operator);
+    }
+    super.visitIndexExpression(node);
+  }
+
+  @override
+  visitMethodInvocation(MethodInvocation node) {
+    SimpleIdentifier name = node.methodName;
+    Element element = name.bestElement;
+    // qualified unresolved name invocation
+    bool isQualified = node.realTarget != null;
+    if (isQualified && element == null) {
+      recordNameRelation(name, IndexRelationKind.IS_INVOKED_BY);
+    }
+    // element invocation
+    IndexRelationKind kind = element is ClassElement
+        ? IndexRelationKind.IS_REFERENCED_BY
+        : IndexRelationKind.IS_INVOKED_BY;
+    recordRelation(element, kind, name, isQualified);
+    node.target?.accept(this);
+    node.argumentList?.accept(this);
+  }
+
+  @override
+  visitPartDirective(PartDirective node) {
+    Element element = node.element;
+    recordUriReference(element, node);
+    super.visitPartDirective(node);
+  }
+
+  @override
+  visitPostfixExpression(PostfixExpression node) {
+    recordOperatorReference(node.operator, node.bestElement);
+    super.visitPostfixExpression(node);
+  }
+
+  @override
+  visitPrefixExpression(PrefixExpression node) {
+    recordOperatorReference(node.operator, node.bestElement);
+    super.visitPrefixExpression(node);
+  }
+
+  @override
+  visitRedirectingConstructorInvocation(RedirectingConstructorInvocation node) {
+    ConstructorElement element = node.staticElement;
+    if (node.constructorName != null) {
+      int offset = node.period.offset;
+      int length = node.constructorName.end - offset;
+      recordRelationOffset(
+          element, IndexRelationKind.IS_REFERENCED_BY, offset, length, true);
+    } else {
+      int offset = node.thisKeyword.end;
+      recordRelationOffset(
+          element, IndexRelationKind.IS_REFERENCED_BY, offset, 0, true);
+    }
+    super.visitRedirectingConstructorInvocation(node);
+  }
+
+  @override
+  visitSimpleIdentifier(SimpleIdentifier node) {
+    Element element = node.bestElement;
+    // name in declaration
+    if (node.inDeclarationContext()) {
+      recordDefinedElement(element);
+      return;
+    }
+    // record qualified unresolved name reference
+    bool isQualified = _isQualified(node);
+    if (isQualified && element == null) {
+      recordNameRelation(node, IndexRelationKind.IS_REFERENCED_BY);
+    }
+    // this.field parameter
+    if (element is FieldFormalParameterElement) {
+      recordRelation(
+          element.field, IndexRelationKind.IS_REFERENCED_BY, node, true);
+      return;
+    }
+    // record specific relations
+    recordRelation(
+        element, IndexRelationKind.IS_REFERENCED_BY, node, isQualified);
+  }
+
+  @override
+  visitSuperConstructorInvocation(SuperConstructorInvocation node) {
+    ConstructorElement element = node.staticElement;
+    if (node.constructorName != null) {
+      int offset = node.period.offset;
+      int length = node.constructorName.end - offset;
+      recordRelationOffset(
+          element, IndexRelationKind.IS_REFERENCED_BY, offset, length, true);
+    } else {
+      int offset = node.superKeyword.end;
+      recordRelationOffset(
+          element, IndexRelationKind.IS_REFERENCED_BY, offset, 0, true);
+    }
+    super.visitSuperConstructorInvocation(node);
+  }
+
+  @override
+  visitTypeName(TypeName node) {
+    AstNode parent = node.parent;
+    if (parent is ClassTypeAlias && parent.superclass == node) {
+      recordSuperType(node, IndexRelationKind.IS_EXTENDED_BY);
+    } else {
+      super.visitTypeName(node);
+    }
+  }
+
+  @override
+  visitWithClause(WithClause node) {
+    for (TypeName typeName in node.mixinTypes) {
+      recordSuperType(typeName, IndexRelationKind.IS_MIXED_IN_BY);
+    }
+  }
+
+  /**
+   * If the given [constructor] is a synthetic constructor created for a
+   * [ClassTypeAlias], return the actual constructor of a [ClassDeclaration]
+   * which is invoked.  Return `null` if a redirection cycle is detected.
+   */
+  ConstructorElement _getActualConstructorElement(
+      ConstructorElement constructor) {
+    Set<ConstructorElement> seenConstructors = new Set<ConstructorElement>();
+    while (constructor != null &&
+        constructor.isSynthetic &&
+        constructor.redirectedConstructor != null) {
+      constructor = constructor.redirectedConstructor;
+      // fail if a cycle is detected
+      if (!seenConstructors.add(constructor)) {
+        return null;
+      }
+    }
+    return constructor;
+  }
+
+  /**
+   * Return `true` if [node] has an explicit or implicit qualifier, so that it
+   * cannot be shadowed by a local declaration.
+   */
+  bool _isQualified(SimpleIdentifier node) {
+    if (node.isQualified) {
+      return true;
+    }
+    AstNode parent = node.parent;
+    return parent is Combinator || parent is Label;
+  }
+}
+
+/**
+ * Information about a single name relation.  Any [_NameRelationInfo] is always
+ * part of a [_UnitIndexAssembler], so [offset] should be understood within the
+ * context of the compilation unit pointed to by the [_UnitIndexAssembler].
+ */
+class _NameRelationInfo {
+  /**
+   * The identifier of the name returned [PackageIndexAssembler._getStringId].
+   */
+  final int nameId;
+  final IndexRelationKind kind;
+  final int offset;
+
+  _NameRelationInfo(this.nameId, this.kind, this.offset);
+}
+
+/**
+ * Assembler of a single [CompilationUnit] index.  The intended usage sequence:
+ *
+ *  - Call [defineName] for each name defined in the compilation unit.
+ *  - Call [addElementRelation] for each element relation found in the
+ *    compilation unit.
+ *  - Call [addNameRelation] for each name relation found in the
+ *    compilation unit.
+ *  - Assign ids to all the [_ElementInfo] objects reachable from
+ *    [elementRelations].
+ *  - Call [assemble] to produce the final unit index.
+ */
+class _UnitIndexAssembler {
+  final PackageIndexAssembler pkg;
+  final int unitId;
+  final List<_DefinedNameInfo> definedNames = <_DefinedNameInfo>[];
+  final List<_ElementRelationInfo> elementRelations = <_ElementRelationInfo>[];
+  final List<_NameRelationInfo> nameRelations = <_NameRelationInfo>[];
+
+  _UnitIndexAssembler(this.pkg, this.unitId);
+
+  void addElementRelation(Element element, IndexRelationKind kind, int offset,
+      int length, bool isQualified) {
+    try {
+      _ElementInfo elementInfo = pkg._getElementInfo(element);
+      elementRelations.add(new _ElementRelationInfo(
+          elementInfo, kind, offset, length, isQualified));
+    } on StateError {}
+  }
+
+  void addNameRelation(String name, IndexRelationKind kind, int offset) {
+    int nameId = pkg._getStringId(name);
+    nameRelations.add(new _NameRelationInfo(nameId, kind, offset));
+  }
+
+  /**
+   * Assemble a new [UnitIndexBuilder] using the information gathered
+   * by [addElementRelation] and [defineName].
+   */
+  UnitIndexBuilder assemble() {
+    definedNames.sort((a, b) {
+      return a.nameId - b.nameId;
+    });
+    elementRelations.sort((a, b) {
+      return a.elementInfo.id - b.elementInfo.id;
+    });
+    nameRelations.sort((a, b) {
+      return a.nameId - b.nameId;
+    });
+    return new UnitIndexBuilder(
+        unit: unitId,
+        definedNames: definedNames.map((n) => n.nameId).toList(),
+        definedNameKinds: definedNames.map((n) => n.kind).toList(),
+        definedNameOffsets: definedNames.map((n) => n.offset).toList(),
+        usedElements: elementRelations.map((r) => r.elementInfo.id).toList(),
+        usedElementKinds: elementRelations.map((r) => r.kind).toList(),
+        usedElementOffsets: elementRelations.map((r) => r.offset).toList(),
+        usedElementLengths: elementRelations.map((r) => r.length).toList(),
+        usedElementIsQualifiedFlags:
+            elementRelations.map((r) => r.isQualified).toList(),
+        usedNames: nameRelations.map((r) => r.nameId).toList(),
+        usedNameKinds: nameRelations.map((r) => r.kind).toList(),
+        usedNameOffsets: nameRelations.map((r) => r.offset).toList());
+  }
+
+  void defineName(String name, IndexNameKind kind, int offset) {
+    int nameId = pkg._getStringId(name);
+    definedNames.add(new _DefinedNameInfo(nameId, kind, offset));
+  }
+}
diff --git a/pkg/analyzer/lib/src/summary/package_bundle_reader.dart b/pkg/analyzer/lib/src/summary/package_bundle_reader.dart
new file mode 100644
index 0000000..a58bfd3
--- /dev/null
+++ b/pkg/analyzer/lib/src/summary/package_bundle_reader.dart
@@ -0,0 +1,224 @@
+import 'dart:io' as io;
+
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/context/cache.dart';
+import 'package:analyzer/src/context/context.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/summary/idl.dart';
+import 'package:analyzer/src/summary/resynthesize.dart';
+import 'package:analyzer/src/summary/summary_sdk.dart';
+import 'package:analyzer/src/task/dart.dart';
+import 'package:analyzer/task/dart.dart';
+import 'package:analyzer/task/model.dart';
+import 'package:path/path.dart' as pathos;
+
+/**
+ * If [uri] has the `package` scheme in form of `package:pkg/file.dart`,
+ * return the `pkg` name.  Otherwise return `null`.
+ */
+String _getPackageName(Uri uri) {
+  if (uri.scheme != 'package') {
+    return null;
+  }
+  String path = uri.path;
+  int index = path.indexOf('/');
+  if (index == -1) {
+    return null;
+  }
+  return path.substring(0, index);
+}
+
+/**
+ * The [ResultProvider] that provides results from input package summaries.
+ */
+class InputPackagesResultProvider extends ResultProvider {
+  final InternalAnalysisContext _context;
+  final Map<String, String> _packageSummaryInputs;
+
+  _FileBasedSummaryResynthesizer _resynthesizer;
+  SummaryResultProvider _sdkProvider;
+
+  InputPackagesResultProvider(this._context, this._packageSummaryInputs) {
+    InternalAnalysisContext sdkContext = _context.sourceFactory.dartSdk.context;
+    _sdkProvider = sdkContext.resultProvider;
+    // Set the type provider to prevent the context from computing it.
+    _context.typeProvider = sdkContext.typeProvider;
+    // Create a chained resynthesizer.
+    _resynthesizer = new _FileBasedSummaryResynthesizer(
+        _sdkProvider.resynthesizer,
+        _context,
+        _context.typeProvider,
+        _context.sourceFactory,
+        _context.analysisOptions.strongMode,
+        _packageSummaryInputs.values.toList());
+  }
+
+  @override
+  bool compute(CacheEntry entry, ResultDescriptor result) {
+    if (_sdkProvider.compute(entry, result)) {
+      return true;
+    }
+    AnalysisTarget target = entry.target;
+    // Only library results are supported for now.
+    if (target is Source) {
+      Uri uri = target.uri;
+      // We know how to server results to input packages.
+      String sourcePackageName = _getPackageName(uri);
+      if (!_packageSummaryInputs.containsKey(sourcePackageName)) {
+        return false;
+      }
+      // Provide known results.
+      String uriString = uri.toString();
+      if (result == LIBRARY_ELEMENT1 ||
+          result == LIBRARY_ELEMENT2 ||
+          result == LIBRARY_ELEMENT3 ||
+          result == LIBRARY_ELEMENT4 ||
+          result == LIBRARY_ELEMENT5 ||
+          result == LIBRARY_ELEMENT6 ||
+          result == LIBRARY_ELEMENT7 ||
+          result == LIBRARY_ELEMENT8 ||
+          result == LIBRARY_ELEMENT ||
+          false) {
+        LibraryElement libraryElement =
+            _resynthesizer.getLibraryElement(uriString);
+        entry.setValue(result, libraryElement, TargetedResult.EMPTY_LIST);
+        return true;
+      } else if (result == READY_LIBRARY_ELEMENT2 ||
+          result == READY_LIBRARY_ELEMENT5 ||
+          result == READY_LIBRARY_ELEMENT6) {
+        entry.setValue(result, true, TargetedResult.EMPTY_LIST);
+        return true;
+      } else if (result == SOURCE_KIND) {
+        if (_resynthesizer.linkedMap.containsKey(uriString)) {
+          entry.setValue(result, SourceKind.LIBRARY, TargetedResult.EMPTY_LIST);
+          return true;
+        }
+        if (_resynthesizer.unlinkedMap.containsKey(uriString)) {
+          entry.setValue(result, SourceKind.PART, TargetedResult.EMPTY_LIST);
+          return true;
+        }
+        return false;
+      }
+    }
+    return false;
+  }
+}
+
+/**
+ * The [UriResolver] that knows about sources that are parts of packages which
+ * are served from their summaries.
+ */
+class InSummaryPackageUriResolver extends UriResolver {
+  final Map<String, String> _packageSummaryInputs;
+
+  InSummaryPackageUriResolver(this._packageSummaryInputs);
+
+  @override
+  Source resolveAbsolute(Uri uri, [Uri actualUri]) {
+    actualUri ??= uri;
+    String packageName = _getPackageName(actualUri);
+    if (_packageSummaryInputs.containsKey(packageName)) {
+      return new _InSummarySource(actualUri);
+    }
+    return null;
+  }
+}
+
+/**
+ * A concrete resynthesizer that serves summaries from given file paths.
+ */
+class _FileBasedSummaryResynthesizer extends SummaryResynthesizer {
+  final Map<String, UnlinkedUnit> unlinkedMap = <String, UnlinkedUnit>{};
+  final Map<String, LinkedLibrary> linkedMap = <String, LinkedLibrary>{};
+
+  _FileBasedSummaryResynthesizer(
+      SummaryResynthesizer parent,
+      AnalysisContext context,
+      TypeProvider typeProvider,
+      SourceFactory sourceFactory,
+      bool strongMode,
+      List<String> summaryPaths)
+      : super(parent, context, typeProvider, sourceFactory, strongMode) {
+    summaryPaths.forEach(_fillMaps);
+  }
+
+  @override
+  LinkedLibrary getLinkedSummary(String uri) {
+    return linkedMap[uri];
+  }
+
+  @override
+  UnlinkedUnit getUnlinkedSummary(String uri) {
+    return unlinkedMap[uri];
+  }
+
+  @override
+  bool hasLibrarySummary(String uri) {
+    return linkedMap.containsKey(uri);
+  }
+
+  void _fillMaps(String path) {
+    io.File file = new io.File(path);
+    List<int> buffer = file.readAsBytesSync();
+    PackageBundle bundle = new PackageBundle.fromBuffer(buffer);
+    for (int i = 0; i < bundle.unlinkedUnitUris.length; i++) {
+      unlinkedMap[bundle.unlinkedUnitUris[i]] = bundle.unlinkedUnits[i];
+    }
+    for (int i = 0; i < bundle.linkedLibraryUris.length; i++) {
+      linkedMap[bundle.linkedLibraryUris[i]] = bundle.linkedLibraries[i];
+    }
+  }
+}
+
+/**
+ * A placeholder of a source that is part of a package whose analysis results
+ * are served from its summary.  This source uses its URI as [fullName] and has
+ * empty contents.
+ */
+class _InSummarySource extends Source {
+  final Uri uri;
+
+  _InSummarySource(this.uri);
+
+  @override
+  TimestampedData<String> get contents => new TimestampedData<String>(0, '');
+
+  @override
+  String get encoding => uri.toString();
+
+  @override
+  String get fullName => encoding;
+
+  @override
+  int get hashCode => uri.hashCode;
+
+  @override
+  bool get isInSystemLibrary => false;
+
+  @override
+  int get modificationStamp => 0;
+
+  @override
+  String get shortName => pathos.basename(fullName);
+
+  @override
+  UriKind get uriKind => UriKind.PACKAGE_URI;
+
+  @override
+  bool operator ==(Object object) =>
+      object is _InSummarySource && object.uri == uri;
+
+  @override
+  bool exists() => true;
+
+  @override
+  Uri resolveRelativeUri(Uri relativeUri) {
+    Uri baseUri = uri;
+    return baseUri.resolveUri(relativeUri);
+  }
+
+  @override
+  String toString() => uri.toString();
+}
diff --git a/pkg/analyzer/lib/src/summary/resynthesize.dart b/pkg/analyzer/lib/src/summary/resynthesize.dart
index 4f6eb20..214861a 100644
--- a/pkg/analyzer/lib/src/summary/resynthesize.dart
+++ b/pkg/analyzer/lib/src/summary/resynthesize.dart
@@ -949,6 +949,7 @@
   void buildClass(UnlinkedClass serializedClass) {
     ClassElementImpl classElement =
         new ClassElementImpl(serializedClass.name, serializedClass.nameOffset);
+    classElement.hasBeenInferred = summaryResynthesizer.strongMode;
     classElement.typeParameters =
         buildTypeParameters(serializedClass.typeParameters);
     classElement.abstract = serializedClass.isAbstract;
@@ -1656,17 +1657,19 @@
   /**
    * Resynthesize a [ParameterElement].
    */
-  ParameterElement buildParameter(UnlinkedParam serializedParameter) {
+  ParameterElement buildParameter(UnlinkedParam serializedParameter,
+      {bool synthetic: false}) {
     ParameterElementImpl parameterElement;
+    int nameOffset = synthetic ? -1 : serializedParameter.nameOffset;
     if (serializedParameter.isInitializingFormal) {
       FieldFormalParameterElementImpl initializingParameter;
       if (serializedParameter.kind == UnlinkedParamKind.required) {
         initializingParameter = new FieldFormalParameterElementImpl(
-            serializedParameter.name, serializedParameter.nameOffset);
+            serializedParameter.name, nameOffset);
       } else {
         DefaultFieldFormalParameterElementImpl defaultParameter =
             new DefaultFieldFormalParameterElementImpl(
-                serializedParameter.name, serializedParameter.nameOffset);
+                serializedParameter.name, nameOffset);
         initializingParameter = defaultParameter;
         if (serializedParameter.defaultValue != null) {
           defaultParameter.constantInitializer =
@@ -1679,12 +1682,12 @@
       initializingParameter.field = fields[serializedParameter.name];
     } else {
       if (serializedParameter.kind == UnlinkedParamKind.required) {
-        parameterElement = new ParameterElementImpl(
-            serializedParameter.name, serializedParameter.nameOffset);
+        parameterElement =
+            new ParameterElementImpl(serializedParameter.name, nameOffset);
       } else {
         DefaultParameterElementImpl defaultParameter =
             new DefaultParameterElementImpl(
-                serializedParameter.name, serializedParameter.nameOffset);
+                serializedParameter.name, nameOffset);
         parameterElement = defaultParameter;
         if (serializedParameter.defaultValue != null) {
           defaultParameter.constantInitializer =
@@ -1694,6 +1697,7 @@
         }
       }
     }
+    parameterElement.synthetic = synthetic;
     buildAnnotations(parameterElement, serializedParameter.annotations);
     if (serializedParameter.isFunctionTyped) {
       FunctionElementImpl parameterTypeElement =
@@ -1784,6 +1788,17 @@
     }
     if (type.paramReference != 0) {
       return getTypeParameterFromScope(type.paramReference);
+    } else if (type.syntheticReturnType != null) {
+      FunctionElementImpl element = new FunctionElementImpl('', -1);
+      element.synthetic = true;
+      element.parameters = type.syntheticParams
+          .map((UnlinkedParam param) => buildParameter(param, synthetic: true))
+          .toList();
+      element.returnType = buildType(type.syntheticReturnType);
+      FunctionTypeImpl result = new FunctionTypeImpl.elementWithNameAndArgs(
+          element, null, null, false);
+      element.type = result;
+      return result;
     } else {
       DartType getTypeArgument(int i) {
         if (i < type.typeArguments.length) {
diff --git a/pkg/analyzer/lib/src/summary/summarize_elements.dart b/pkg/analyzer/lib/src/summary/summarize_elements.dart
index afd3ab1..3d9896b 100644
--- a/pkg/analyzer/lib/src/summary/summarize_elements.dart
+++ b/pkg/analyzer/lib/src/summary/summarize_elements.dart
@@ -4,6 +4,8 @@
 
 library serialization.elements;
 
+import 'dart:convert';
+
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/element.dart';
@@ -17,6 +19,7 @@
 import 'package:analyzer/src/summary/idl.dart';
 import 'package:analyzer/src/summary/name_filter.dart';
 import 'package:analyzer/src/summary/summarize_const_expr.dart';
+import 'package:crypto/crypto.dart';
 
 /**
  * Serialize all the elements in [lib] to a summary using [ctx] as the context
@@ -24,7 +27,8 @@
  */
 LibrarySerializationResult serializeLibrary(
     LibraryElement lib, TypeProvider typeProvider, bool strongMode) {
-  var serializer = new _LibrarySerializer(lib, typeProvider, strongMode);
+  _LibrarySerializer serializer =
+      new _LibrarySerializer(lib, typeProvider, strongMode);
   LinkedLibraryBuilder linked = serializer.serializeLibrary();
   return new LibrarySerializationResult(linked, serializer.unlinkedUnits,
       serializer.unitUris, serializer.unitSources);
@@ -106,6 +110,76 @@
 }
 
 /**
+ * Object that gathers information uses it to assemble a new
+ * [PackageBundleBuilder].
+ */
+class PackageBundleAssembler {
+  /**
+   * Value that will be stored in [PackageBundle.majorVersion] for any summaries
+   * created by this code.  When making a breaking change to the summary format,
+   * this value should be incremented by 1 and [currentMinorVersion] should be
+   * reset to zero.
+   */
+  static const int currentMajorVersion = 1;
+
+  /**
+   * Value that will be stored in [PackageBundle.minorVersion] for any summaries
+   * created by this code.  When making a non-breaking change to the summary
+   * format that clients might need to be aware of (such as adding a kind of
+   * data that was previously not summarized), this value should be incremented
+   * by 1.
+   */
+  static const int currentMinorVersion = 0;
+
+  final List<String> _linkedLibraryUris = <String>[];
+  final List<LinkedLibraryBuilder> _linkedLibraries = <LinkedLibraryBuilder>[];
+  final List<String> _unlinkedUnitUris = <String>[];
+  final List<UnlinkedUnitBuilder> _unlinkedUnits = <UnlinkedUnitBuilder>[];
+  final List<String> _unlinkedUnitHashes = <String>[];
+
+  /**
+   * Assemble a new [PackageBundleBuilder] using the gathered information.
+   */
+  PackageBundleBuilder assemble() {
+    return new PackageBundleBuilder(
+        linkedLibraryUris: _linkedLibraryUris,
+        linkedLibraries: _linkedLibraries,
+        unlinkedUnitUris: _unlinkedUnitUris,
+        unlinkedUnits: _unlinkedUnits,
+        unlinkedUnitHashes: _unlinkedUnitHashes,
+        majorVersion: currentMajorVersion,
+        minorVersion: currentMinorVersion);
+  }
+
+  /**
+   * Serialize the library with the given [element].
+   */
+  void serializeLibraryElement(LibraryElement element) {
+    String uri = element.source.uri.toString();
+    LibrarySerializationResult libraryResult = serializeLibrary(
+        element,
+        element.context.typeProvider,
+        element.context.analysisOptions.strongMode);
+    _linkedLibraryUris.add(uri);
+    _linkedLibraries.add(libraryResult.linked);
+    _unlinkedUnitUris.addAll(libraryResult.unitUris);
+    _unlinkedUnits.addAll(libraryResult.unlinkedUnits);
+    for (Source source in libraryResult.unitSources) {
+      _unlinkedUnitHashes.add(_hash(source.contents.data));
+    }
+  }
+
+  /**
+   * Compute a hash of the given file contents.
+   */
+  String _hash(String contents) {
+    MD5 md5 = new MD5();
+    md5.add(UTF8.encode(contents));
+    return CryptoUtils.bytesToHex(md5.close());
+  }
+}
+
+/**
  * Instances of this class keep track of intermediate state during
  * serialization of a single compilation unit.
  */
@@ -185,6 +259,12 @@
    */
   int bottomReferenceIndex = null;
 
+  /**
+   * If `true`, we are currently generating linked references, so new
+   * references will be not stored in [unlinkedReferences].
+   */
+  bool buildingLinkedReferences = false;
+
   _CompilationUnitSerializer(
       this.librarySerializer, this.compilationUnit, this.unitNum);
 
@@ -317,9 +397,11 @@
    * found during [addCompilationUnitElements].
    */
   void createLinkedTypes() {
+    buildingLinkedReferences = true;
     linkedUnit.types = deferredLinkedTypes
         .map((_SerializeTypeRef closure) => closure())
         .toList();
+    buildingLinkedReferences = false;
   }
 
   /**
@@ -728,7 +810,7 @@
     context ??= parameter;
     UnlinkedParamBuilder b = new UnlinkedParamBuilder();
     b.name = parameter.name;
-    b.nameOffset = parameter.nameOffset;
+    b.nameOffset = parameter.nameOffset >= 0 ? parameter.nameOffset : 0;
     switch (parameter.parameterKind) {
       case ParameterKind.REQUIRED:
         b.kind = UnlinkedParamKind.required;
@@ -794,11 +876,8 @@
 
   /**
    * Compute the reference index which should be stored in a [EntityRef].
-   *
-   * If [linked] is true, and a new reference has to be created, the reference
-   * will only be stored in [linkedReferences].
    */
-  int serializeReferenceForType(DartType type, bool linked) {
+  int serializeReferenceForType(DartType type) {
     Element element = type.element;
     LibraryElement dependentLibrary = element?.library;
     if (dependentLibrary == null) {
@@ -806,7 +885,7 @@
         // References to the "bottom" type are always implicit, since there is
         // no way to explicitly refer to the "bottom" type.  Therefore they
         // should always be linked.
-        assert(linked);
+        assert(buildingLinkedReferences);
         return serializeBottomReference();
       }
       assert(type.isDynamic || type.isVoid);
@@ -816,7 +895,7 @@
       // Note: for a type which is truly `dynamic` or `void`, fall through to
       // use [_getElementReferenceId].
     }
-    return _getElementReferenceId(element, linked: linked);
+    return _getElementReferenceId(element);
   }
 
   /**
@@ -853,26 +932,36 @@
 
   /**
    * Serialize the given [type] into a [EntityRef].  If [slot] is provided,
-   * it should be included in the [EntityRef].  If [linked] is true, any
-   * references that are created will be populated into [linkedReferences] but
-   * not [unlinkedReferences].
+   * it should be included in the [EntityRef].
    *
    * [context] is the element within which the [EntityRef] will be
    * interpreted; this is used to serialize type parameters.
    */
   EntityRefBuilder serializeTypeRef(DartType type, Element context,
-      {bool linked: false, int slot}) {
+      {int slot}) {
+    if (slot != null) {
+      assert(buildingLinkedReferences);
+    }
     EntityRefBuilder b = new EntityRefBuilder(slot: slot);
+    Element typeElement = type.element;
     if (type is TypeParameterType) {
       b.paramReference = findTypeParameterIndex(type, context);
+    } else if (type is FunctionType &&
+        typeElement is FunctionElement &&
+        typeElement.enclosingElement == null) {
+      b.syntheticReturnType =
+          serializeTypeRef(typeElement.returnType, typeElement);
+      b.syntheticParams = typeElement.parameters
+          .map((ParameterElement param) => serializeParam(param, context))
+          .toList();
     } else {
       if (type is FunctionType &&
-          type.element.enclosingElement is ParameterElement) {
+          typeElement.enclosingElement is ParameterElement) {
         // Code cannot refer to function types implicitly defined by parameters
         // directly, so if we get here, we must be serializing a linked
         // reference from type inference.
-        assert(linked);
-        ParameterElement parameterElement = type.element.enclosingElement;
+        assert(buildingLinkedReferences);
+        ParameterElement parameterElement = typeElement.enclosingElement;
         while (true) {
           Element parent = parameterElement.enclosingElement;
           if (parent is ExecutableElement) {
@@ -885,7 +974,7 @@
               continue;
             } else {
               // Function-typed parameter inside a top level function or method.
-              b.reference = _getElementReferenceId(parent, linked: linked);
+              b.reference = _getElementReferenceId(parent);
               break;
             }
           } else {
@@ -894,7 +983,7 @@
           }
         }
       } else {
-        b.reference = serializeReferenceForType(type, linked);
+        b.reference = serializeReferenceForType(type);
       }
       List<DartType> typeArguments = getTypeArguments(type);
       if (typeArguments != null) {
@@ -907,8 +996,8 @@
         if (numArgsToSerialize > 0) {
           List<EntityRefBuilder> serializedArguments = <EntityRefBuilder>[];
           for (int i = 0; i < numArgsToSerialize; i++) {
-            serializedArguments.add(
-                serializeTypeRef(typeArguments[i], context, linked: linked));
+            serializedArguments
+                .add(serializeTypeRef(typeArguments[i], context));
           }
           b.typeArguments = serializedArguments;
         }
@@ -1027,12 +1116,12 @@
     int slot = ++numSlots;
     if (type != null) {
       deferredLinkedTypes
-          .add(() => serializeTypeRef(type, context, linked: true, slot: slot));
+          .add(() => serializeTypeRef(type, context, slot: slot));
     }
     return slot;
   }
 
-  int _getElementReferenceId(Element element, {bool linked: false}) {
+  int _getElementReferenceId(Element element) {
     return referenceMap.putIfAbsent(element, () {
       LibraryElement dependentLibrary = librarySerializer.libraryElement;
       int unit = 0;
@@ -1049,13 +1138,13 @@
       String name = element == null ? 'void' : element.name;
       int index;
       LinkedReferenceBuilder linkedReference;
-      if (linked) {
+      if (buildingLinkedReferences) {
         linkedReference =
             new LinkedReferenceBuilder(kind: kind, unit: unit, name: name);
         if (enclosingElement != null &&
             enclosingElement is! CompilationUnitElement) {
           linkedReference.containingReference =
-              _getElementReferenceId(enclosingElement, linked: linked);
+              _getElementReferenceId(enclosingElement);
           if (enclosingElement is ClassElement) {
             // Nothing to do.
           } else if (enclosingElement is ExecutableElement) {
@@ -1095,7 +1184,7 @@
             prefixReference = serializePrefix(prefix);
           }
         } else {
-          prefixReference = _getElementReferenceId(enclosing, linked: linked);
+          prefixReference = _getElementReferenceId(enclosing);
         }
         index = serializeUnlinkedReference(name, kind,
             prefixReference: prefixReference, unit: unit);
@@ -1331,7 +1420,7 @@
   /**
    * Retrieve a list of the Sources for the compilation units in the library.
    */
-  List<String> get unitSources => compilationUnitSerializers
+  List<Source> get unitSources => compilationUnitSerializers
       .map((_CompilationUnitSerializer s) => s.unitSource)
       .toList();
 
diff --git a/pkg/analyzer/lib/src/task/dart.dart b/pkg/analyzer/lib/src/task/dart.dart
index d21914c..b94806d 100644
--- a/pkg/analyzer/lib/src/task/dart.dart
+++ b/pkg/analyzer/lib/src/task/dart.dart
@@ -29,7 +29,6 @@
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
-import 'package:analyzer/src/generated/visitors.dart';
 import 'package:analyzer/src/plugin/engine_plugin.dart';
 import 'package:analyzer/src/services/lint.dart';
 import 'package:analyzer/src/task/driver.dart';
@@ -1939,7 +1938,7 @@
     // and the invalidation code (invalidateLibraryCycles) will ensure that
     // element model results will be re-used here only if they are still valid.
     if (context.analysisOptions.strongMode) {
-      LibraryElementImpl library = getRequiredInput(LIBRARY_ELEMENT_INPUT);
+      LibraryElement library = getRequiredInput(LIBRARY_ELEMENT_INPUT);
       List<LibraryElement> component = library.libraryCycle;
       Set<LibraryElement> filter = new Set<LibraryElement>.from(component);
       Set<CompilationUnitElement> deps = new Set<CompilationUnitElement>();
@@ -2266,7 +2265,7 @@
   static const String PARSED_UNIT_INPUT = 'PARSED_UNIT_INPUT';
 
   // Prefix for comments ignoring error codes.
-  static const String _normalizedIgnorePrefix = '//#ignore:';
+  static const String _normalizedIgnorePrefix = '//ignore:';
 
   DartErrorsTask(InternalAnalysisContext context, AnalysisTarget target)
       : super(context, target);
@@ -3365,6 +3364,7 @@
     parser.parseAsync = options.enableAsync;
     parser.parseFunctionBodies = options.analyzeFunctionBodiesPredicate(source);
     parser.parseGenericMethods = options.enableGenericMethods;
+    parser.parseConditionalDirectives = options.enableConditionalDirectives;
     parser.parseGenericMethodComments = options.strongMode;
     CompilationUnit unit = parser.parseCompilationUnit(tokenStream);
     unit.lineInfo = lineInfo;
diff --git a/pkg/analyzer/lib/src/task/options.dart b/pkg/analyzer/lib/src/task/options.dart
index 9b96c6a..e598910 100644
--- a/pkg/analyzer/lib/src/task/options.dart
+++ b/pkg/analyzer/lib/src/task/options.dart
@@ -47,6 +47,8 @@
   static const String enableAsync = 'enableAsync';
   static const String enableGenericMethods = 'enableGenericMethods';
   static const String enableSuperMixins = 'enableSuperMixins';
+  static const String enableConditionalDirectives =
+      "enableConditionalDirectives";
   static const String errors = 'errors';
   static const String exclude = 'exclude';
   static const String language = 'language';
@@ -79,7 +81,8 @@
   static const List<String> languageOptions = const [
     enableAsync,
     enableGenericMethods,
-    enableSuperMixins
+    enableSuperMixins,
+    enableConditionalDirectives,
   ];
 }
 
@@ -490,6 +493,14 @@
         context.analysisOptions = options;
       }
     }
+    if (feature == AnalyzerOptions.enableConditionalDirectives) {
+      if (isTrue(value)) {
+        AnalysisOptionsImpl options =
+            new AnalysisOptionsImpl.from(context.analysisOptions);
+        options.enableConditionalDirectives = true;
+        context.analysisOptions = options;
+      }
+    }
   }
 
   void setLanguageOptions(AnalysisContext context, Object configs) {
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index bb328c2..fb6756b 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
 name: analyzer
-version: 0.27.2
+version: 0.27.3-alpha.0
 author: Dart Team <misc@dartlang.org>
 description: Static analyzer for Dart.
 homepage: http://www.dartlang.org
diff --git a/pkg/analyzer/test/generated/all_the_rest_test.dart b/pkg/analyzer/test/generated/all_the_rest_test.dart
index 5d74e2c..b7ed4b3 100644
--- a/pkg/analyzer/test/generated/all_the_rest_test.dart
+++ b/pkg/analyzer/test/generated/all_the_rest_test.dart
@@ -660,6 +660,7 @@
         AstFactory.classDeclaration(null, className, null, null, null, null);
     classDeclaration.documentationComment = AstFactory.documentationComment(
         [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
+    classDeclaration.endToken.offset = 80;
     classDeclaration.accept(builder);
     List<ClassElement> types = holder.types;
     expect(types, hasLength(1));
@@ -673,6 +674,7 @@
     expect(type.isSynthetic, isFalse);
     expect(type.documentationComment, '/// aaa');
     _assertHasDocRange(type, 50, 7);
+    _assertHasCodeRange(type, 50, 31);
   }
 
   void test_visitClassDeclaration_parameterized() {
@@ -837,6 +839,26 @@
     expect(type.typeParameters[0].name, equals('T'));
   }
 
+  void test_visitCompilationUnit_codeRange() {
+    TopLevelVariableDeclaration topLevelVariableDeclaration = AstFactory
+        .topLevelVariableDeclaration(null, AstFactory.typeName4('int'),
+            [AstFactory.variableDeclaration('V')]);
+    CompilationUnit unit = new CompilationUnit(
+        topLevelVariableDeclaration.beginToken,
+        null,
+        [],
+        [topLevelVariableDeclaration],
+        topLevelVariableDeclaration.endToken);
+    ElementHolder holder = new ElementHolder();
+    ElementBuilder builder = _makeBuilder(holder);
+    unit.beginToken.offset = 10;
+    unit.endToken.offset = 40;
+    unit.accept(builder);
+
+    CompilationUnitElement element = builder.compilationUnitElement;
+    _assertHasCodeRange(element, 0, 41);
+  }
+
   void test_visitConstructorDeclaration_external() {
     ElementHolder holder = new ElementHolder();
     ElementBuilder builder = _makeBuilder(holder);
@@ -909,12 +931,14 @@
     constructorDeclaration.documentationComment = AstFactory
         .documentationComment(
             [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
+    constructorDeclaration.endToken.offset = 80;
     constructorDeclaration.accept(builder);
 
     List<ConstructorElement> constructors = holder.constructors;
     expect(constructors, hasLength(1));
     ConstructorElement constructor = constructors[0];
     expect(constructor, isNotNull);
+    _assertHasCodeRange(constructor, 50, 31);
     expect(constructor.documentationComment, '/// aaa');
     _assertHasDocRange(constructor, 50, 7);
     expect(constructor.isExternal, isFalse);
@@ -993,11 +1017,14 @@
         AstFactory.declaredIdentifier3(variableName);
     AstFactory.forEachStatement(
         identifier, AstFactory.nullLiteral(), AstFactory.emptyStatement());
+    identifier.beginToken.offset = 50;
+    identifier.endToken.offset = 80;
     identifier.accept(builder);
 
     List<LocalVariableElement> variables = holder.localVariables;
     expect(variables, hasLength(1));
     LocalVariableElement variable = variables[0];
+    _assertHasCodeRange(variable, 50, 31);
     expect(variable, isNotNull);
     expect(variable.hasImplicitType, isTrue);
     expect(variable.isConst, isFalse);
@@ -1019,12 +1046,15 @@
         AstFactory.declaredIdentifier4(AstFactory.typeName4('E'), variableName);
     AstFactory.forEachStatement(
         identifier, AstFactory.nullLiteral(), AstFactory.emptyStatement());
+    identifier.beginToken.offset = 50;
+    identifier.endToken.offset = 80;
     identifier.accept(builder);
 
     List<LocalVariableElement> variables = holder.localVariables;
     expect(variables, hasLength(1));
     LocalVariableElement variable = variables[0];
     expect(variable, isNotNull);
+    _assertHasCodeRange(variable, 50, 31);
     expect(variable.hasImplicitType, isFalse);
     expect(variable.isConst, isFalse);
     expect(variable.isDeprecated, isFalse);
@@ -1045,11 +1075,14 @@
         AstFactory.positionalFormalParameter(
             AstFactory.simpleFormalParameter3(parameterName),
             AstFactory.integer(0));
+    formalParameter.beginToken.offset = 50;
+    formalParameter.endToken.offset = 80;
     formalParameter.accept(builder);
 
     List<ParameterElement> parameters = holder.parameters;
     expect(parameters, hasLength(1));
     ParameterElement parameter = parameters[0];
+    _assertHasCodeRange(parameter, 50, 31);
     expect(parameter.hasImplicitType, isTrue);
     expect(parameter.initializer, isNotNull);
     expect(parameter.initializer.type, isNotNull);
@@ -1102,11 +1135,13 @@
         AstFactory.enumDeclaration2(enumName, ["ONE"]);
     enumDeclaration.documentationComment = AstFactory.documentationComment(
         [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
+    enumDeclaration.endToken.offset = 80;
     enumDeclaration.accept(builder);
     List<ClassElement> enums = holder.enums;
     expect(enums, hasLength(1));
     ClassElement enumElement = enums[0];
     expect(enumElement, isNotNull);
+    _assertHasCodeRange(enumElement, 50, 31);
     expect(enumElement.documentationComment, '/// aaa');
     _assertHasDocRange(enumElement, 50, 7);
     expect(enumElement.name, enumName);
@@ -1124,6 +1159,7 @@
     ]);
     fieldDeclaration.documentationComment = AstFactory.documentationComment(
         [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
+    fieldDeclaration.endToken.offset = 110;
     fieldDeclaration.accept(builder);
 
     List<FieldElement> fields = holder.fields;
@@ -1131,6 +1167,7 @@
 
     FieldElement firstField = fields[0];
     expect(firstField, isNotNull);
+    _assertHasCodeRange(firstField, 50, 61);
     expect(firstField.documentationComment, '/// aaa');
     _assertHasDocRange(firstField, 50, 7);
     expect(firstField.name, firstFieldName);
@@ -1141,6 +1178,7 @@
 
     FieldElement secondField = fields[1];
     expect(secondField, isNotNull);
+    _assertHasCodeRange(secondField, 50, 61);
     expect(secondField.documentationComment, '/// aaa');
     _assertHasDocRange(secondField, 50, 7);
     expect(secondField.name, secondFieldName);
@@ -1156,11 +1194,14 @@
     String parameterName = "p";
     FieldFormalParameter formalParameter =
         AstFactory.fieldFormalParameter(null, null, parameterName);
+    formalParameter.beginToken.offset = 50;
+    formalParameter.endToken.offset = 80;
     formalParameter.accept(builder);
     List<ParameterElement> parameters = holder.parameters;
     expect(parameters, hasLength(1));
     ParameterElement parameter = parameters[0];
     expect(parameter, isNotNull);
+    _assertHasCodeRange(parameter, 50, 31);
     expect(parameter.name, parameterName);
     expect(parameter.initializer, isNull);
     expect(parameter.isConst, isFalse);
@@ -1251,12 +1292,14 @@
             AstFactory.formalParameterList(), AstFactory.blockFunctionBody2()));
     declaration.documentationComment = AstFactory.documentationComment(
         [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
+    declaration.endToken.offset = 80;
     declaration.accept(builder);
 
     List<PropertyAccessorElement> accessors = holder.accessors;
     expect(accessors, hasLength(1));
     PropertyAccessorElement accessor = accessors[0];
     expect(accessor, isNotNull);
+    _assertHasCodeRange(accessor, 50, 31);
     expect(accessor.documentationComment, '/// aaa');
     _assertHasDocRange(accessor, 50, 7);
     expect(accessor.name, functionName);
@@ -1287,12 +1330,14 @@
             AstFactory.formalParameterList(), AstFactory.blockFunctionBody2()));
     declaration.documentationComment = AstFactory.documentationComment(
         [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
+    declaration.endToken.offset = 80;
     declaration.accept(builder);
 
     List<FunctionElement> functions = holder.functions;
     expect(functions, hasLength(1));
     FunctionElement function = functions[0];
     expect(function, isNotNull);
+    _assertHasCodeRange(function, 50, 31);
     expect(function.documentationComment, '/// aaa');
     _assertHasDocRange(function, 50, 7);
     expect(function.hasImplicitReturnType, isFalse);
@@ -1317,12 +1362,14 @@
             AstFactory.formalParameterList(), AstFactory.blockFunctionBody2()));
     declaration.documentationComment = AstFactory.documentationComment(
         [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
+    declaration.endToken.offset = 80;
     declaration.accept(builder);
 
     List<PropertyAccessorElement> accessors = holder.accessors;
     expect(accessors, hasLength(1));
     PropertyAccessorElement accessor = accessors[0];
     expect(accessor, isNotNull);
+    _assertHasCodeRange(accessor, 50, 31);
     expect(accessor.documentationComment, '/// aaa');
     _assertHasDocRange(accessor, 50, 7);
     expect(accessor.hasImplicitReturnType, isTrue);
@@ -1396,12 +1443,14 @@
         null, aliasName, AstFactory.typeParameterList([parameterName]), null);
     aliasNode.documentationComment = AstFactory.documentationComment(
         [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
+    aliasNode.endToken.offset = 80;
     aliasNode.accept(builder);
 
     List<FunctionTypeAliasElement> aliases = holder.typeAliases;
     expect(aliases, hasLength(1));
     FunctionTypeAliasElement alias = aliases[0];
     expect(alias, isNotNull);
+    _assertHasCodeRange(alias, 50, 31);
     expect(alias.documentationComment, '/// aaa');
     _assertHasDocRange(alias, 50, 7);
     expect(alias.name, aliasName);
@@ -1557,6 +1606,7 @@
         AstFactory.blockFunctionBody2());
     methodDeclaration.documentationComment = AstFactory.documentationComment(
         [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
+    methodDeclaration.endToken.offset = 80;
     methodDeclaration.accept(builder);
 
     List<FieldElement> fields = holder.fields;
@@ -1568,6 +1618,7 @@
     expect(field.setter, isNull);
     PropertyAccessorElement getter = field.getter;
     expect(getter, isNotNull);
+    _assertHasCodeRange(getter, 50, 31);
     expect(getter.documentationComment, '/// aaa');
     _assertHasDocRange(getter, 50, 7);
     expect(getter.hasImplicitReturnType, isTrue);
@@ -1673,12 +1724,14 @@
         AstFactory.blockFunctionBody2());
     methodDeclaration.documentationComment = AstFactory.documentationComment(
         [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
+    methodDeclaration.endToken.offset = 80;
     methodDeclaration.accept(builder);
 
     List<MethodElement> methods = holder.methods;
     expect(methods, hasLength(1));
     MethodElement method = methods[0];
     expect(method, isNotNull);
+    _assertHasCodeRange(method, 50, 31);
     expect(method.documentationComment, '/// aaa');
     _assertHasDocRange(method, 50, 7);
     expect(method.hasImplicitReturnType, isFalse);
@@ -1742,6 +1795,7 @@
         AstFactory.blockFunctionBody2());
     methodDeclaration.documentationComment = AstFactory.documentationComment(
         [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
+    methodDeclaration.endToken.offset = 80;
     methodDeclaration.accept(builder);
 
     List<FieldElement> fields = holder.fields;
@@ -1754,6 +1808,7 @@
 
     PropertyAccessorElement setter = field.setter;
     expect(setter, isNotNull);
+    _assertHasCodeRange(setter, 50, 31);
     expect(setter.documentationComment, '/// aaa');
     _assertHasDocRange(setter, 50, 7);
     expect(setter.hasImplicitReturnType, isTrue);
@@ -1983,11 +2038,14 @@
         AstFactory.simpleFormalParameter3(parameterName),
         AstFactory.identifier3("42"));
     _useParameterInMethod(formalParameter, 100, 110);
+    formalParameter.beginToken.offset = 50;
+    formalParameter.endToken.offset = 80;
     formalParameter.accept(builder);
     List<ParameterElement> parameters = holder.parameters;
     expect(parameters, hasLength(1));
     ParameterElement parameter = parameters[0];
     expect(parameter, isNotNull);
+    _assertHasCodeRange(parameter, 50, 32);
     expect(parameter.name, parameterName);
     expect(parameter.isConst, isFalse);
     expect(parameter.isFinal, isFalse);
@@ -2088,11 +2146,14 @@
           AstFactory.simpleFormalParameter3(firstParameterName),
           AstFactory.simpleFormalParameter3(secondParameterName)
         ]));
+    typeAlias.beginToken.offset = 50;
+    typeAlias.endToken.offset = 80;
     typeAlias.accept(builder);
     List<FunctionTypeAliasElement> aliases = holder.typeAliases;
     expect(aliases, hasLength(1));
     FunctionTypeAliasElement alias = aliases[0];
     expect(alias, isNotNull);
+    _assertHasCodeRange(alias, 50, 31);
     expect(alias.name, aliasName);
     expect(alias.type, isNotNull);
     expect(alias.isSynthetic, isFalse);
@@ -2139,11 +2200,13 @@
     ElementBuilder builder = _makeBuilder(holder);
     String parameterName = "E";
     TypeParameter typeParameter = AstFactory.typeParameter(parameterName);
+    typeParameter.beginToken.offset = 50;
     typeParameter.accept(builder);
     List<TypeParameterElement> typeParameters = holder.typeParameters;
     expect(typeParameters, hasLength(1));
     TypeParameterElement typeParameterElement = typeParameters[0];
     expect(typeParameterElement, isNotNull);
+    _assertHasCodeRange(typeParameterElement, 50, 1);
     expect(typeParameterElement.name, parameterName);
     expect(typeParameterElement.bound, isNull);
     expect(typeParameterElement.isSynthetic, isFalse);
@@ -2158,8 +2221,8 @@
     String variableName = "v";
     VariableDeclaration variable =
         AstFactory.variableDeclaration2(variableName, null);
-    Statement statement =
-        AstFactory.variableDeclarationStatement2(null, [variable]);
+    VariableDeclarationStatement statement =
+        AstFactory.variableDeclarationStatement2(Keyword.VAR, [variable]);
     ConstructorDeclaration constructor = AstFactory.constructorDeclaration2(
         null,
         null,
@@ -2168,6 +2231,8 @@
         AstFactory.formalParameterList(),
         null,
         AstFactory.blockFunctionBody2([statement]));
+    statement.beginToken.offset = 50;
+    statement.endToken.offset = 80;
     constructor.accept(builder);
 
     List<ConstructorElement> constructors = holder.constructors;
@@ -2176,6 +2241,7 @@
         constructors[0].localVariables;
     expect(variableElements, hasLength(1));
     LocalVariableElement variableElement = variableElements[0];
+    _assertHasCodeRange(variableElement, 50, 31);
     expect(variableElement.hasImplicitType, isTrue);
     expect(variableElement.name, variableName);
   }
@@ -2354,6 +2420,12 @@
     expect(variable.setter, isNull);
   }
 
+  void _assertHasCodeRange(Element element, int offset, int length) {
+    ElementImpl elementImpl = element;
+    expect(elementImpl.codeOffset, offset);
+    expect(elementImpl.codeLength, length);
+  }
+
   void _assertHasDocRange(
       Element element, int expectedOffset, int expectedLength) {
     // Cast to dynamic here to avoid a hint about @deprecated docRange.
diff --git a/pkg/analyzer/test/generated/compile_time_error_code_test.dart b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
index 7c0c15a..09485aa 100644
--- a/pkg/analyzer/test/generated/compile_time_error_code_test.dart
+++ b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
@@ -7,10 +7,12 @@
 import 'package:analyzer/src/generated/error.dart';
 import 'package:analyzer/src/generated/parser.dart' show ParserErrorCode;
 import 'package:analyzer/src/generated/source_io.dart';
+import 'package:unittest/unittest.dart' show expect;
 
 import '../reflective_tests.dart';
 import '../utils.dart';
 import 'resolver_test.dart';
+import 'package:analyzer/src/generated/engine.dart';
 
 main() {
   initializeTestEnvironment();
@@ -6043,6 +6045,41 @@
     assertErrors(source, [CompileTimeErrorCode.URI_DOES_NOT_EXIST]);
   }
 
+  void test_uriDoesNotExist_import_disappears_when_fixed() {
+    Source source = addSource("import 'target.dart';");
+    computeLibrarySourceErrors(source);
+    assertErrors(source, [CompileTimeErrorCode.URI_DOES_NOT_EXIST]);
+
+    // Check that the file is represented as missing.
+    Source target =
+        analysisContext2.getSourcesWithFullName("/target.dart").first;
+    expect(analysisContext2.getModificationStamp(target), -1);
+
+    // Add an overlay in the same way as AnalysisServer.
+    analysisContext2
+      ..setContents(target, "")
+      ..handleContentsChanged(target, null, "", true);
+
+    // Make sure the error goes away.
+    computeLibrarySourceErrors(source);
+    assertErrors(source, [HintCode.UNUSED_IMPORT]);
+  }
+
+  void test_uriDoesNotExist_import_appears_after_deleting_target() {
+    Source test = addSource("import 'target.dart';");
+    Source target = addNamedSource("/target.dart", "");
+    computeLibrarySourceErrors(test);
+    assertErrors(test, [HintCode.UNUSED_IMPORT]);
+
+    // Remove the overlay in the same way as AnalysisServer.
+    analysisContext2.setContents(target, null);
+    ChangeSet changeSet = new ChangeSet()..removedSource(target);
+    analysisContext2.applyChanges(changeSet);
+
+    computeLibrarySourceErrors(test);
+    assertErrors(test, [CompileTimeErrorCode.URI_DOES_NOT_EXIST]);
+  }
+
   void test_uriDoesNotExist_part() {
     Source source = addSource(r'''
 library lib;
diff --git a/pkg/analyzer/test/generated/declaration_resolver_test.dart b/pkg/analyzer/test/generated/declaration_resolver_test.dart
index 0f1112d..4f0b214 100644
--- a/pkg/analyzer/test/generated/declaration_resolver_test.dart
+++ b/pkg/analyzer/test/generated/declaration_resolver_test.dart
@@ -302,6 +302,26 @@
     expect(setterName.staticElement, same(setterElement));
   }
 
+  void test_visitExportDirective_notExistingSource() {
+    String code = r'''
+export 'foo.dart';
+''';
+    CompilationUnit unit = resolveSource(code);
+    // re-resolve
+    _cloneResolveUnit(unit);
+    // no other validations than built into DeclarationResolver
+  }
+
+  void test_visitExportDirective_unresolvedUri() {
+    String code = r'''
+export 'package:foo/bar.dart';
+''';
+    CompilationUnit unit = resolveSource(code);
+    // re-resolve
+    _cloneResolveUnit(unit);
+    // no other validations than built into DeclarationResolver
+  }
+
   void test_visitFunctionExpression() {
     String code = r'''
 main(List<String> items) {
@@ -314,12 +334,19 @@
     // no other validations than built into DeclarationResolver
   }
 
-  void test_visitMethodDeclaration_unaryMinus() {
+  void test_visitImportDirective_notExistingSource() {
     String code = r'''
-class C {
-  C operator -() => null;
-  C operator -(C other) => null;
-}
+import 'foo.dart';
+''';
+    CompilationUnit unit = resolveSource(code);
+    // re-resolve
+    _cloneResolveUnit(unit);
+    // no other validations than built into DeclarationResolver
+  }
+
+  void test_visitImportDirective_unresolvedUri() {
+    String code = r'''
+import 'package:foo/bar.dart';
 ''';
     CompilationUnit unit = resolveSource(code);
     // re-resolve
@@ -409,6 +436,29 @@
     expect(firstName.staticElement, same(firstElement));
     expect(secondName.staticElement, same(secondElement));
   }
+
+  void test_visitMethodDeclaration_unaryMinus() {
+    String code = r'''
+class C {
+  C operator -() => null;
+  C operator -(C other) => null;
+}
+''';
+    CompilationUnit unit = resolveSource(code);
+    // re-resolve
+    _cloneResolveUnit(unit);
+    // no other validations than built into DeclarationResolver
+  }
+
+  void test_visitPartDirective_notExistingSource() {
+    String code = r'''
+part 'foo.bar';
+''';
+    CompilationUnit unit = resolveSource(code);
+    // re-resolve
+    _cloneResolveUnit(unit);
+    // no other validations than built into DeclarationResolver
+  }
 }
 
 /**
diff --git a/pkg/analyzer/test/generated/error_suppression_test.dart b/pkg/analyzer/test/generated/error_suppression_test.dart
index 560a2c2..da6c49d 100644
--- a/pkg/analyzer/test/generated/error_suppression_test.dart
+++ b/pkg/analyzer/test/generated/error_suppression_test.dart
@@ -19,7 +19,7 @@
 class ErrorSuppressionTest extends ResolverTestCase {
   void test_error_code_mismatch() {
     Source source = addSource('''
-//# ignore: const_initialized_with_non_constant_value
+// ignore: const_initialized_with_non_constant_value
 int x = '';
 const y = x; //CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
 ''');
@@ -32,7 +32,7 @@
 
   void test_ignore_first() {
     Source source = addSource('''
-//# ignore: invalid_assignment
+// ignore: invalid_assignment
 int x = '';
 // ... but no ignore here ...
 const y = x; //CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
@@ -46,7 +46,7 @@
     Source source = addSource('''
 //INVALID_ASSIGNMENT
 int x = '';
-//# ignore: const_initialized_with_non_constant_value
+// ignore: const_initialized_with_non_constant_value
 const y = x; //CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
 ''');
     computeLibrarySourceErrors(source);
@@ -55,7 +55,7 @@
 
   void test_invalid_error_code() {
     Source source = addSource('''
-//# ignore: right_format_wrong_code
+// ignore: right_format_wrong_code
 int x = '';
 const y = x; //CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
 ''');
@@ -69,7 +69,7 @@
   void test_missing_error_codes() {
     Source source = addSource('''
     int x = 3;
-//# ignore:
+// ignore:
 const String y = x; //INVALID_ASSIGNMENT, CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
 ''');
     computeLibrarySourceErrors(source);
@@ -79,9 +79,9 @@
     ]);
   }
 
-  void test_missing_metadata_prefix() {
+  void test_missing_metadata_suffix() {
     Source source = addSource('''
-// ignore: invalid_assignment
+// ignore invalid_assignment
 String y = 3; //INVALID_ASSIGNMENT
 ''');
     computeLibrarySourceErrors(source);
@@ -91,7 +91,7 @@
   void test_multiple_comments() {
     Source source = addSource('''
 int x = ''; //This is the first comment...
-//# ignore: const_initialized_with_non_constant_value
+// ignore: const_initialized_with_non_constant_value
 const y = x; //CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
 ''');
     computeLibrarySourceErrors(source);
@@ -101,7 +101,7 @@
   void test_multiple_ignores() {
     Source source = addSource('''
 int x = 3;
-//# ignore: invalid_assignment, const_initialized_with_non_constant_value
+// ignore: invalid_assignment, const_initialized_with_non_constant_value
 const String y = x; //INVALID_ASSIGNMENT, CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
 ''');
     computeLibrarySourceErrors(source);
@@ -111,7 +111,7 @@
   void test_multiple_ignores_whitespace_variant_1() {
     Source source = addSource('''
 int x = 3;
-//#ignore:invalid_assignment,const_initialized_with_non_constant_value
+//ignore:invalid_assignment,const_initialized_with_non_constant_value
 const String y = x; //INVALID_ASSIGNMENT, CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
 ''');
     computeLibrarySourceErrors(source);
@@ -121,7 +121,7 @@
   void test_multiple_ignores_whitespace_variant_2() {
     Source source = addSource('''
 int x = 3;
-//#ignore: invalid_assignment,const_initialized_with_non_constant_value
+//ignore: invalid_assignment,const_initialized_with_non_constant_value
 const String y = x; //INVALID_ASSIGNMENT, CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
 ''');
     computeLibrarySourceErrors(source);
@@ -131,7 +131,7 @@
   void test_multiple_ignores_whitespace_variant_3() {
     Source source = addSource('''
 int x = 3;
-//# ignore: invalid_assignment,const_initialized_with_non_constant_value
+// ignore: invalid_assignment,const_initialized_with_non_constant_value
 const String y = x; //INVALID_ASSIGNMENT, CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
 ''');
     computeLibrarySourceErrors(source);
diff --git a/pkg/analyzer/test/generated/parser_test.dart b/pkg/analyzer/test/generated/parser_test.dart
index 710be9b..19a2a89 100644
--- a/pkg/analyzer/test/generated/parser_test.dart
+++ b/pkg/analyzer/test/generated/parser_test.dart
@@ -4016,6 +4016,33 @@
     expect(metadata[0].name.name, "override");
   }
 
+  void test_missingSemicolon_varialeDeclarationList() {
+    void verify(CompilationUnitMember member, String expectedTypeName,
+        String expectedName, String expectedSemicolon) {
+      expect(member, new isInstanceOf<TopLevelVariableDeclaration>());
+      TopLevelVariableDeclaration declaration = member;
+      VariableDeclarationList variableList = declaration.variables;
+      expect(variableList, isNotNull);
+      NodeList<VariableDeclaration> variables = variableList.variables;
+      expect(variables, hasLength(1));
+      VariableDeclaration variable = variables[0];
+      expect(variableList.type.toString(), expectedTypeName);
+      expect(variable.name.name, expectedName);
+      expect(declaration.semicolon.lexeme, expectedSemicolon);
+    }
+
+    CompilationUnit unit = ParserTestCase.parseCompilationUnit(
+        'String n x = "";', [
+      ParserErrorCode.EXPECTED_TOKEN,
+      ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE
+    ]);
+    expect(unit, isNotNull);
+    NodeList<CompilationUnitMember> declarations = unit.declarations;
+    expect(declarations, hasLength(2));
+    verify(declarations[0], 'String', 'n', '');
+    verify(declarations[1], 'null', 'x', ';');
+  }
+
   void test_multiplicativeExpression_missing_LHS() {
     BinaryExpression expression =
         parseExpression("* y", [ParserErrorCode.MISSING_IDENTIFIER]);
@@ -4222,6 +4249,24 @@
 
 @reflectiveTest
 class ResolutionCopierTest extends EngineTestCase {
+  void test_visitAdjacentStrings() {
+    AdjacentStrings createNode() => new AdjacentStrings([
+          new SimpleStringLiteral(null, 'hello'),
+          new SimpleStringLiteral(null, 'world')
+        ]);
+
+    AdjacentStrings fromNode = createNode();
+    DartType propagatedType = ElementFactory.classElement2("A").type;
+    fromNode.propagatedType = propagatedType;
+    DartType staticType = ElementFactory.classElement2("B").type;
+    fromNode.staticType = staticType;
+
+    AdjacentStrings toNode = createNode();
+    ResolutionCopier.copyResolutionData(fromNode, toNode);
+    expect(toNode.propagatedType, same(propagatedType));
+    expect(toNode.staticType, same(staticType));
+  }
+
   void test_visitAnnotation() {
     String annotationName = "proxy";
     Annotation fromNode =
@@ -4429,20 +4474,16 @@
     MethodElement propagatedElement = ElementFactory.methodElement(
         "m", ElementFactory.classElement2("C").type);
     fromNode.propagatedElement = propagatedElement;
-    DartType propagatedType = ElementFactory.classElement2("C").type;
-    fromNode.propagatedType = propagatedType;
     MethodElement staticElement = ElementFactory.methodElement(
         "m", ElementFactory.classElement2("C").type);
     fromNode.staticElement = staticElement;
-    DartType staticType = ElementFactory.classElement2("C").type;
-    fromNode.staticType = staticType;
     FunctionExpressionInvocation toNode =
         AstFactory.functionExpressionInvocation(AstFactory.identifier3("f"));
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
+
+    _copyAndVerifyInvocation(fromNode, toNode);
+
     expect(toNode.propagatedElement, same(propagatedElement));
-    expect(toNode.propagatedType, same(propagatedType));
     expect(toNode.staticElement, same(staticElement));
-    expect(toNode.staticType, same(staticType));
   }
 
   void test_visitImportDirective() {
@@ -4564,14 +4605,8 @@
 
   void test_visitMethodInvocation() {
     MethodInvocation fromNode = AstFactory.methodInvocation2("m");
-    DartType propagatedType = ElementFactory.classElement2("C").type;
-    fromNode.propagatedType = propagatedType;
-    DartType staticType = ElementFactory.classElement2("C").type;
-    fromNode.staticType = staticType;
     MethodInvocation toNode = AstFactory.methodInvocation2("m");
-    ResolutionCopier.copyResolutionData(fromNode, toNode);
-    expect(toNode.propagatedType, same(propagatedType));
-    expect(toNode.staticType, same(staticType));
+    _copyAndVerifyInvocation(fromNode, toNode);
   }
 
   void test_visitNamedExpression() {
@@ -4848,6 +4883,25 @@
     ResolutionCopier.copyResolutionData(fromNode, toNode);
     expect(toNode.type, same(type));
   }
+
+  void _copyAndVerifyInvocation(
+      InvocationExpression fromNode, InvocationExpression toNode) {
+    DartType propagatedType = ElementFactory.classElement2("C").type;
+    fromNode.propagatedType = propagatedType;
+    DartType staticType = ElementFactory.classElement2("C").type;
+    fromNode.staticType = staticType;
+
+    DartType propagatedInvokeType = ElementFactory.classElement2("C").type;
+    fromNode.propagatedInvokeType = propagatedInvokeType;
+    DartType staticInvokeType = ElementFactory.classElement2("C").type;
+    fromNode.staticInvokeType = staticInvokeType;
+
+    ResolutionCopier.copyResolutionData(fromNode, toNode);
+    expect(toNode.propagatedType, same(propagatedType));
+    expect(toNode.staticType, same(staticType));
+    expect(toNode.propagatedInvokeType, same(propagatedInvokeType));
+    expect(toNode.staticInvokeType, same(staticInvokeType));
+  }
 }
 
 /**
diff --git a/pkg/analyzer/test/generated/resolver_test.dart b/pkg/analyzer/test/generated/resolver_test.dart
index 339d4d1..41d96a5 100644
--- a/pkg/analyzer/test/generated/resolver_test.dart
+++ b/pkg/analyzer/test/generated/resolver_test.dart
@@ -12,6 +12,8 @@
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/context/context.dart';
+import 'package:analyzer/src/dart/ast/ast.dart'
+    show SimpleIdentifierImpl, PrefixedIdentifierImpl;
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/member.dart';
 import 'package:analyzer/src/dart/element/type.dart';
@@ -33,6 +35,7 @@
 import 'package:analyzer/src/generated/testing/test_type_provider.dart';
 import 'package:analyzer/src/generated/testing/token_factory.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
+import 'package:analyzer/src/string_source.dart';
 import 'package:unittest/unittest.dart';
 
 import '../reflective_tests.dart';
@@ -100,6 +103,12 @@
     return initContextWithCore(context);
   }
 
+  static InternalAnalysisContext contextWithCoreAndPackages(
+      Map<String, String> packages) {
+    AnalysisContextForTests context = new AnalysisContextForTests();
+    return initContextWithCore(context, new TestPackageUriResolver(packages));
+  }
+
   /**
    * Initialize the given analysis context with a fake core library already resolved.
    *
@@ -107,12 +116,19 @@
    * @return the analysis context that was created
    */
   static InternalAnalysisContext initContextWithCore(
-      InternalAnalysisContext context) {
+      InternalAnalysisContext context,
+      [UriResolver contributedResolver]) {
     DirectoryBasedDartSdk sdk = new _AnalysisContextFactory_initContextWithCore(
         new JavaFile("/fake/sdk"),
         enableAsync: context.analysisOptions.enableAsync);
-    SourceFactory sourceFactory =
-        new SourceFactory([new DartUriResolver(sdk), new FileUriResolver()]);
+    List<UriResolver> resolvers = <UriResolver>[
+      new DartUriResolver(sdk),
+      new FileUriResolver()
+    ];
+    if (contributedResolver != null) {
+      resolvers.add(contributedResolver);
+    }
+    SourceFactory sourceFactory = new SourceFactory(resolvers);
     context.sourceFactory = sourceFactory;
     AnalysisContext coreContext = sdk.context;
     (coreContext.analysisOptions as AnalysisOptionsImpl).strongMode =
@@ -2467,6 +2483,21 @@
     verify([source, source2, source3]);
   }
 
+  @override
+  void reset() {
+    analysisContext2 = AnalysisContextFactory.contextWithCoreAndPackages({
+      'package:meta/meta.dart': r'''
+library meta;
+
+const _Protected protected = const _Protected();
+
+class _Protected {
+  const _Protected();
+}
+'''
+    });
+  }
+
   void test_argumentTypeNotAssignable_functionType() {
     Source source = addSource(r'''
 m() {
@@ -3303,6 +3334,241 @@
     verify([source]);
   }
 
+  void test_invalidUseOfProtectedMember_field() {
+    Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+  @protected
+  int a;
+}
+abstract class B implements A {
+  int b() => a;
+}''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source, [HintCode.INVALID_USE_OF_PROTECTED_MEMBER]);
+    verify([source]);
+  }
+
+  void test_invalidUseOfProtectedMember_function() {
+    Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+  @protected
+  void a(){ }
+}
+main() {
+  new A().a();
+}''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source, [HintCode.INVALID_USE_OF_PROTECTED_MEMBER]);
+    verify([source]);
+  }
+
+  void test_invalidUseOfProtectedMember_getter() {
+    Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+  @protected
+  int get a => 42;
+}
+abstract class B implements A {
+  int b() => a;
+}''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source, [HintCode.INVALID_USE_OF_PROTECTED_MEMBER]);
+    verify([source]);
+  }
+
+  void test_invalidUseOfProtectedMember_message() {
+    Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+  @protected
+  void a(){ }
+}
+class B {
+  void b() => new A().a();
+}''');
+    List<AnalysisError> errors = analysisContext2.computeErrors(source);
+    expect(errors, hasLength(1));
+    expect(errors[0].message,
+        "The member 'a' can only be used within instance members of subclasses of 'A'");
+  }
+
+  void test_invalidUseOfProtectedMember_method_1() {
+    Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+  @protected
+  void a(){ }
+}
+class B {
+  void b() => new A().a();
+}''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source, [HintCode.INVALID_USE_OF_PROTECTED_MEMBER]);
+    verify([source]);
+  }
+
+  void test_invalidUseOfProtectedMember_method_2() {
+    Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+  @protected
+  void a(){ }
+}
+abstract class B implements A {
+  void b() => a();
+}''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source, [HintCode.INVALID_USE_OF_PROTECTED_MEMBER]);
+    verify([source]);
+  }
+
+  void test_invalidUseOfProtectedMember_OK_1() {
+    Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+  @protected
+  void a(){ }
+}
+class B extends A {
+  void b() => a();
+}''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source, []);
+    verify([source]);
+  }
+
+  void test_invalidUseOfProtectedMember_OK_2() {
+    Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+  @protected
+  void a(){ }
+}
+class B extends Object with A {
+  void b() => a();
+}''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source, []);
+    verify([source]);
+  }
+
+  void test_invalidUseOfProtectedMember_OK_3() {
+    Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+  @protected m1() {}
+}
+class B extends A {
+  static m2(A a) => a.m1();
+}''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source, []);
+    verify([source]);
+  }
+
+  void test_invalidUseOfProtectedMember_OK_4() {
+    Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+  @protected
+  void a(){ }
+}
+class B extends A {
+  void a() => a();
+}
+main() {
+  new B().a();
+}''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source, []);
+    verify([source]);
+  }
+
+  void test_invalidUseOfProtectedMember_OK_field() {
+    Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+  @protected
+  int a = 42;
+}
+class B extends A {
+  int b() => a;
+}
+''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source, []);
+    verify([source]);
+  }
+
+  void test_invalidUseOfProtectedMember_OK_getter() {
+    Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+  @protected
+  int get a => 42;
+}
+class B extends A {
+  int b() => a;
+}
+''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source, []);
+    verify([source]);
+  }
+
+  void test_invalidUseOfProtectedMember_OK_setter() {
+    Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+  @protected
+  void set a(int i) { }
+}
+class B extends A {
+  void b(int i) {
+    a = i;
+  }
+}
+''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source, []);
+    verify([source]);
+  }
+
+  void test_invalidUseOfProtectedMember_setter() {
+    Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+  @protected
+  void set a(int i) { }
+}
+abstract class B implements A {
+  b(int i) {
+    a = i;
+  }
+}''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source, [HintCode.INVALID_USE_OF_PROTECTED_MEMBER]);
+    verify([source]);
+  }
+
+  void test_invalidUseOfProtectedMember_topLevelVariable() {
+    Source source = addSource(r'''
+import 'package:meta/meta.dart';
+@protected
+int x = 0;
+main() {
+  print(x);
+}''');
+    computeLibrarySourceErrors(source);
+    // TODO(brianwilkerson) This should produce a hint because the annotation is
+    // being applied to the wrong kind of declaration.
+    assertNoErrors(source);
+    verify([source]);
+  }
+
   void test_isDouble() {
     AnalysisOptionsImpl options = new AnalysisOptionsImpl();
     options.dart2jsHint = true;
@@ -8006,6 +8272,7 @@
       [List<ErrorCode> expectedErrorCodes = ErrorCode.EMPTY_LIST]) {
     GatheringErrorListener errorListener = new GatheringErrorListener();
     for (AnalysisError error in analysisContext2.computeErrors(source)) {
+      expect(error.source, source);
       ErrorCode errorCode = error.errorCode;
       if (!enableUnusedElement &&
           (errorCode == HintCode.UNUSED_ELEMENT ||
@@ -8230,6 +8497,7 @@
 
   @override
   void setUp() {
+    ElementFactory.flushStaticState();
     super.setUp();
     reset();
   }
@@ -14410,6 +14678,23 @@
   }
 }
 
+class TestPackageUriResolver extends UriResolver {
+  Map<Uri, Source> sourceMap = new HashMap<Uri, Source>();
+
+  TestPackageUriResolver(Map<String, String> map) {
+    map.forEach((String uri, String contents) {
+      sourceMap[Uri.parse(uri)] =
+          new StringSource(contents, '/test_pkg_source.dart');
+    });
+  }
+
+  @override
+  Source resolveAbsolute(Uri uri, [Uri actualUri]) => sourceMap[uri];
+
+  @override
+  Uri restoreAbsolute(Source source) => throw new UnimplementedError();
+}
+
 @reflectiveTest
 class TypeOverrideManagerTest extends EngineTestCase {
   void test_exitScope_noScopes() {
@@ -16792,6 +17077,30 @@
     _listener.assertNoErrors();
   }
 
+  void test_visitTypeName_noParameters_noArguments_undefined() {
+    SimpleIdentifier id = AstFactory.identifier3("unknown")
+      ..staticElement = new _StaleElement();
+    TypeName typeName = new TypeName(id, null);
+    _resolveNode(typeName, []);
+    expect(typeName.type, UndefinedTypeImpl.instance);
+    expect(typeName.name.staticElement, null);
+    _listener.assertErrorsWithCodes([StaticWarningCode.UNDEFINED_CLASS]);
+  }
+
+  void test_visitTypeName_prefixed_noParameters_noArguments_undefined() {
+    SimpleIdentifier prefix = AstFactory.identifier3("unknownPrefix")
+      ..staticElement = new _StaleElement();
+    SimpleIdentifier suffix = AstFactory.identifier3("unknownSuffix")
+      ..staticElement = new _StaleElement();
+    TypeName typeName =
+        new TypeName(AstFactory.identifier(prefix, suffix), null);
+    _resolveNode(typeName, []);
+    expect(typeName.type, UndefinedTypeImpl.instance);
+    expect(prefix.staticElement, null);
+    expect(suffix.staticElement, null);
+    _listener.assertErrorsWithCodes([StaticWarningCode.UNDEFINED_CLASS]);
+  }
+
   void test_visitTypeName_parameters_arguments() {
     ClassElement classA = ElementFactory.classElement2("A", ["E"]);
     ClassElement classB = ElementFactory.classElement2("B");
@@ -16952,6 +17261,21 @@
 }
 
 /**
+ * Represents an element left over from a previous resolver run.
+ *
+ * A _StaleElement should always be replaced with either null or a new Element.
+ */
+class _StaleElement extends ElementImpl {
+  _StaleElement() : super("_StaleElement", -1);
+
+  @override
+  accept(_) => throw "_StaleElement shouldn't be visited";
+
+  @override
+  get kind => throw "_StaleElement's kind shouldn't be accessed";
+}
+
+/**
  * Shared infrastructure for [StaticTypeAnalyzer2Test] and
  * [StrongModeStaticTypeAnalyzer2Test].
  */
diff --git a/pkg/analyzer/test/generated/test_support.dart b/pkg/analyzer/test/generated/test_support.dart
index 51f5fcd..239c42b 100644
--- a/pkg/analyzer/test/generated/test_support.dart
+++ b/pkg/analyzer/test/generated/test_support.dart
@@ -580,9 +580,7 @@
     return new TimestampedData<String>(0, _contents);
   }
 
-  String get encoding {
-    throw new UnsupportedOperationException();
-  }
+  String get encoding => _name;
 
   String get fullName {
     return _name;
diff --git a/pkg/analyzer/test/src/abstract_single_unit.dart b/pkg/analyzer/test/src/abstract_single_unit.dart
new file mode 100644
index 0000000..48ba251
--- /dev/null
+++ b/pkg/analyzer/test/src/abstract_single_unit.dart
@@ -0,0 +1,109 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library test.services.src.index.abstract_single_file;
+
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/java_engine.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:unittest/unittest.dart';
+
+import 'context/abstract_context.dart';
+
+class AbstractSingleUnitTest extends AbstractContextTest {
+  bool verifyNoTestUnitErrors = true;
+
+  String testCode;
+  String testFile = '/test.dart';
+  Source testSource;
+  CompilationUnit testUnit;
+  CompilationUnitElement testUnitElement;
+  LibraryElement testLibraryElement;
+
+  void addTestSource(String code, [Uri uri]) {
+    testCode = code;
+    testSource = addSource(testFile, code);
+  }
+
+  void assertNoErrorsInSource(Source source) {
+    List<AnalysisError> errors = context.getErrors(source).errors;
+    expect(errors, isEmpty);
+  }
+
+  Element findElement(String name, [ElementKind kind]) {
+    return findChildElement(testUnitElement, name, kind);
+  }
+
+  int findEnd(String search) {
+    return findOffset(search) + search.length;
+  }
+
+  /**
+   * Returns the [SimpleIdentifier] at the given search pattern.
+   */
+  SimpleIdentifier findIdentifier(String search) {
+    return findNodeAtString(search, (node) => node is SimpleIdentifier);
+  }
+
+  AstNode findNodeAtOffset(int offset, [Predicate<AstNode> predicate]) {
+    AstNode result = new NodeLocator(offset).searchWithin(testUnit);
+    if (result != null && predicate != null) {
+      result = result.getAncestor(predicate);
+    }
+    return result;
+  }
+
+  AstNode findNodeAtString(String search, [Predicate<AstNode> predicate]) {
+    int offset = findOffset(search);
+    return findNodeAtOffset(offset, predicate);
+  }
+
+  Element findNodeElementAtString(String search,
+      [Predicate<AstNode> predicate]) {
+    AstNode node = findNodeAtString(search, predicate);
+    if (node == null) {
+      return null;
+    }
+    return ElementLocator.locate(node);
+  }
+
+  int findOffset(String search) {
+    int offset = testCode.indexOf(search);
+    expect(offset, isNonNegative, reason: "Not found '$search' in\n$testCode");
+    return offset;
+  }
+
+  int getLeadingIdentifierLength(String search) {
+    int length = 0;
+    while (length < search.length) {
+      int c = search.codeUnitAt(length);
+      if (c >= 'a'.codeUnitAt(0) && c <= 'z'.codeUnitAt(0)) {
+        length++;
+        continue;
+      }
+      if (c >= 'A'.codeUnitAt(0) && c <= 'Z'.codeUnitAt(0)) {
+        length++;
+        continue;
+      }
+      if (c >= '0'.codeUnitAt(0) && c <= '9'.codeUnitAt(0)) {
+        length++;
+        continue;
+      }
+      break;
+    }
+    return length;
+  }
+
+  void resolveTestUnit(String code) {
+    addTestSource(code);
+    testUnit = resolveLibraryUnit(testSource);
+    if (verifyNoTestUnitErrors) {
+      assertNoErrorsInSource(testSource);
+    }
+    testUnitElement = testUnit.element;
+    testLibraryElement = testUnitElement.library;
+  }
+}
diff --git a/pkg/analyzer/test/src/context/abstract_context.dart b/pkg/analyzer/test/src/context/abstract_context.dart
index 18bde46..b0b7a01 100644
--- a/pkg/analyzer/test/src/context/abstract_context.dart
+++ b/pkg/analyzer/test/src/context/abstract_context.dart
@@ -4,7 +4,9 @@
 
 library analyzer.test.src.context.abstract_context;
 
+import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/visitor.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/file_system/memory_file_system.dart';
 import 'package:analyzer/src/context/cache.dart';
@@ -20,6 +22,28 @@
 
 import 'mock_sdk.dart';
 
+/**
+ * Finds an [Element] with the given [name].
+ */
+Element findChildElement(Element root, String name, [ElementKind kind]) {
+  Element result = null;
+  root.accept(new _ElementVisitorFunctionWrapper((Element element) {
+    if (element.name != name) {
+      return;
+    }
+    if (kind != null && element.kind != kind) {
+      return;
+    }
+    result = element;
+  }));
+  return result;
+}
+
+/**
+ * A function to be called for every [Element].
+ */
+typedef void _ElementVisitorFunction(Element element);
+
 class AbstractContextTest {
   MemoryResourceProvider resourceProvider = new MemoryResourceProvider();
 
@@ -124,6 +148,10 @@
     analysisDriver = context.driver;
   }
 
+  CompilationUnit resolveLibraryUnit(Source source) {
+    return context.resolveCompilationUnit2(source, source);
+  }
+
   void setUp() {
     List<Plugin> plugins = <Plugin>[];
     plugins.addAll(AnalysisEngine.instance.requiredPlugins);
@@ -138,3 +166,18 @@
 
   void tearDown() {}
 }
+
+/**
+ * Wraps the given [_ElementVisitorFunction] into an instance of
+ * [GeneralizingElementVisitor].
+ */
+class _ElementVisitorFunctionWrapper extends GeneralizingElementVisitor {
+  final _ElementVisitorFunction function;
+
+  _ElementVisitorFunctionWrapper(this.function);
+
+  visitElement(Element element) {
+    function(element);
+    super.visitElement(element);
+  }
+}
diff --git a/pkg/analyzer/test/src/context/context_test.dart b/pkg/analyzer/test/src/context/context_test.dart
index cbcfacf..d7e0a58 100644
--- a/pkg/analyzer/test/src/context/context_test.dart
+++ b/pkg/analyzer/test/src/context/context_test.dart
@@ -2548,7 +2548,7 @@
       expect(unitA.element, same(unitElementA));
       expect(unitElementA.library, same(libraryElementA));
     }
-    // Update a.dart, rename A to A2, invalidates b.dart, so
+    // Add method to a.dart. This invalidates b.dart, so
     // we know that the previous update did not damage dependencies.
     context.setContents(
         sourceA,
@@ -2760,8 +2760,10 @@
   }
 
   void _assertInvalid(AnalysisTarget target, ResultDescriptor descriptor) {
-    CacheState state = analysisCache.getState(target, descriptor);
-    expect(state, CacheState.INVALID);
+    CacheState actual = analysisCache.getState(target, descriptor);
+    if (actual != CacheState.INVALID) {
+      fail("cache state of $target $descriptor: wanted INVALID, got: $actual");
+    }
   }
 
   void _assertValid(AnalysisTarget target, ResultDescriptor descriptor) {
diff --git a/pkg/analyzer/test/src/context/mock_sdk.dart b/pkg/analyzer/test/src/context/mock_sdk.dart
index 7d85c4f..5466949 100644
--- a/pkg/analyzer/test/src/context/mock_sdk.dart
+++ b/pkg/analyzer/test/src/context/mock_sdk.dart
@@ -36,7 +36,9 @@
     const <String, String>{
       '/lib/async/stream.dart': r'''
 part of dart.async;
-class Stream<T> {}
+class Stream<T> {
+  Future<T> get first;
+}
 abstract class StreamTransformer<S, T> {}
 '''
     });
@@ -112,6 +114,7 @@
   num operator *(num other);
   num operator /(num other);
   int toInt();
+  double toDouble();
   num abs();
   int round();
 }
@@ -140,6 +143,7 @@
 abstract class Iterable<E> {
   Iterator<E> get iterator;
   bool get isEmpty;
+  E get first;
 
   Iterable/*<R>*/ map/*<R>*/(/*=R*/ f(E e));
 
diff --git a/pkg/analyzer/test/src/summary/flat_buffers_test.dart b/pkg/analyzer/test/src/summary/flat_buffers_test.dart
index 361973b..076df23 100644
--- a/pkg/analyzer/test/src/summary/flat_buffers_test.dart
+++ b/pkg/analyzer/test/src/summary/flat_buffers_test.dart
@@ -55,6 +55,34 @@
     }, throwsStateError);
   }
 
+  void test_file_identifier() {
+    Uint8List byteList;
+    {
+      Builder builder = new Builder(initialSize: 0);
+      builder.startTable();
+      Offset offset = builder.endTable();
+      byteList = builder.finish(offset, 'Az~ÿ');
+    }
+    // Convert byteList to a ByteData so that we can read data from it.
+    ByteData byteData = byteList.buffer.asByteData(byteList.offsetInBytes);
+    // First 4 bytes are an offset to the table data.
+    int tableDataLoc = byteData.getUint32(0, Endianness.LITTLE_ENDIAN);
+    // Next 4 bytes are the file identifier.
+    expect(byteData.getUint8(4), 65); // 'a'
+    expect(byteData.getUint8(5), 122); // 'z'
+    expect(byteData.getUint8(6), 126); // '~'
+    expect(byteData.getUint8(7), 255); // 'ÿ'
+    // First 4 bytes of the table data are a backwards offset to the vtable.
+    int vTableLoc = tableDataLoc -
+        byteData.getInt32(tableDataLoc, Endianness.LITTLE_ENDIAN);
+    // First 2 bytes of the vtable are the size of the vtable in bytes, which
+    // should be 4.
+    expect(byteData.getUint16(vTableLoc, Endianness.LITTLE_ENDIAN), 4);
+    // Next 2 bytes are the size of the object in bytes (including the vtable
+    // pointer), which should be 4.
+    expect(byteData.getUint16(vTableLoc + 2, Endianness.LITTLE_ENDIAN), 4);
+  }
+
   void test_low() {
     Builder builder = new Builder(initialSize: 0);
     builder.lowReset();
@@ -164,6 +192,47 @@
     expect(items, orderedEquals(values));
   }
 
+  void test_writeList_ofBool() {
+    void verifyListBooleans(int len, List<int> trueBits) {
+      // write
+      List<int> byteList;
+      {
+        Builder builder = new Builder(initialSize: 0);
+        List<bool> values = new List<bool>.filled(len, false);
+        for (int bit in trueBits) {
+          values[bit] = true;
+        }
+        Offset offset = builder.writeListBool(values);
+        byteList = builder.finish(offset);
+      }
+      // read and verify
+      BufferPointer root = new BufferPointer.fromBytes(byteList);
+      List<bool> items = const BoolListReader().read(root);
+      expect(items, hasLength(len));
+      for (int i = 0; i < items.length; i++) {
+        expect(items[i], trueBits.contains(i), reason: 'bit $i of $len');
+      }
+    }
+    verifyListBooleans(0, <int>[]);
+    verifyListBooleans(1, <int>[]);
+    verifyListBooleans(1, <int>[0]);
+    verifyListBooleans(31, <int>[0, 1]);
+    verifyListBooleans(31, <int>[1, 2, 24, 25, 30]);
+    verifyListBooleans(31, <int>[0, 30]);
+    verifyListBooleans(32, <int>[1, 2, 24, 25, 31]);
+    verifyListBooleans(33, <int>[1, 2, 24, 25, 32]);
+    verifyListBooleans(33, <int>[1, 2, 24, 25, 31, 32]);
+    verifyListBooleans(63, <int>[]);
+    verifyListBooleans(63, <int>[0, 1, 2, 61, 62]);
+    verifyListBooleans(63, new List<int>.generate(63, (i) => i));
+    verifyListBooleans(64, <int>[]);
+    verifyListBooleans(64, <int>[0, 1, 2, 61, 62, 63]);
+    verifyListBooleans(64, <int>[1, 2, 62]);
+    verifyListBooleans(64, <int>[0, 1, 2, 63]);
+    verifyListBooleans(64, new List<int>.generate(64, (i) => i));
+    verifyListBooleans(100, <int>[0, 3, 30, 60, 90, 99]);
+  }
+
   void test_writeList_ofFloat64() {
     List<double> values = <double>[-1.234567, 3.4E+9, -5.6E-13, 7.8, 12.13];
     // write
diff --git a/pkg/analyzer/test/src/summary/index_unit_test.dart b/pkg/analyzer/test/src/summary/index_unit_test.dart
new file mode 100644
index 0000000..bfa331f
--- /dev/null
+++ b/pkg/analyzer/test/src/summary/index_unit_test.dart
@@ -0,0 +1,936 @@
+// 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 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/summary/format.dart';
+import 'package:analyzer/src/summary/idl.dart';
+import 'package:analyzer/src/summary/index_unit.dart';
+import 'package:unittest/unittest.dart';
+
+import '../../reflective_tests.dart';
+import '../abstract_single_unit.dart';
+
+main() {
+  groupSep = ' | ';
+  runReflectiveTests(PackageIndexAssemblerTest);
+}
+
+class ExpectedLocation {
+  final CompilationUnitElement unitElement;
+  final int offset;
+  final int length;
+  final bool isQualified;
+
+  ExpectedLocation(
+      this.unitElement, this.offset, this.length, this.isQualified);
+
+  @override
+  String toString() {
+    return '(unit=$unitElement; offset=$offset; length=$length;'
+        ' isQualified=$isQualified)';
+  }
+}
+
+@reflectiveTest
+class PackageIndexAssemblerTest extends AbstractSingleUnitTest {
+  PackageIndex packageIndex;
+  UnitIndex unitIndex;
+
+  _ElementIndexAssert assertThat(Element element) {
+    return new _ElementIndexAssert(this, element);
+  }
+
+  _NameIndexAssert assertThatName(String name) {
+    return new _NameIndexAssert(this, name);
+  }
+
+  CompilationUnitElement importedUnit({int index: 0}) {
+    List<ImportElement> imports = testLibraryElement.imports;
+    return imports[index].importedLibrary.definingCompilationUnit;
+  }
+
+  void test_definedName_classMember_field() {
+    _indexTestUnit('''
+class A {
+  int f;
+}''');
+    _assertDefinedName('f', IndexNameKind.classMember, 'f;');
+  }
+
+  void test_definedName_classMember_getter() {
+    _indexTestUnit('''
+class A {
+  int get g => 0;
+}''');
+    _assertDefinedName('g', IndexNameKind.classMember, 'g => 0;');
+  }
+
+  void test_definedName_classMember_method() {
+    _indexTestUnit('''
+class A {
+  m() {}
+}''');
+    _assertDefinedName('m', IndexNameKind.classMember, 'm() {}');
+  }
+
+  void test_definedName_classMember_operator() {
+    _indexTestUnit('''
+class A {
+  operator +(o) {}
+}''');
+    _assertDefinedName('+', IndexNameKind.classMember, '+(o) {}');
+  }
+
+  void test_definedName_classMember_setter() {
+    _indexTestUnit('''
+class A {
+  int set s (_) {}
+}''');
+    _assertDefinedName('s', IndexNameKind.classMember, 's (_) {}');
+  }
+
+  void test_definedName_topLevel_class() {
+    _indexTestUnit('class A {}');
+    _assertDefinedName('A', IndexNameKind.topLevel, 'A {}');
+  }
+
+  void test_definedName_topLevel_classAlias() {
+    _indexTestUnit('''
+class M {}
+class C = Object with M;''');
+    _assertDefinedName('C', IndexNameKind.topLevel, 'C =');
+  }
+
+  void test_definedName_topLevel_enum() {
+    _indexTestUnit('enum E {a, b, c}');
+    _assertDefinedName('E', IndexNameKind.topLevel, 'E {');
+  }
+
+  void test_definedName_topLevel_function() {
+    _indexTestUnit('foo() {}');
+    _assertDefinedName('foo', IndexNameKind.topLevel, 'foo() {}');
+  }
+
+  void test_definedName_topLevel_functionTypeAlias() {
+    _indexTestUnit('typedef F(int p);');
+    _assertDefinedName('F', IndexNameKind.topLevel, 'F(int p);');
+  }
+
+  void test_definedName_topLevel_getter() {
+    _indexTestUnit('''
+int get g => 0;
+''');
+    _assertDefinedName('g', IndexNameKind.topLevel, 'g => 0;');
+  }
+
+  void test_definedName_topLevel_setter() {
+    _indexTestUnit('''
+int set s (_) {}
+''');
+    _assertDefinedName('s', IndexNameKind.topLevel, 's (_) {}');
+  }
+
+  void test_definedName_topLevel_topLevelVariable() {
+    _indexTestUnit('var V = 42;');
+    _assertDefinedName('V', IndexNameKind.topLevel, 'V = 42;');
+  }
+
+  void test_isExtendedBy_ClassDeclaration() {
+    _indexTestUnit('''
+class A {} // 1
+class B extends A {} // 2
+''');
+    ClassElement elementA = findElement('A');
+    assertThat(elementA)
+      ..isExtendedAt('A {} // 2', true)
+      ..isReferencedAt('A {} // 2', true);
+  }
+
+  void test_isExtendedBy_ClassDeclaration_isQualified() {
+    addSource(
+        '/lib.dart',
+        '''
+class A {}
+''');
+    _indexTestUnit('''
+import 'lib.dart' as p;
+class B extends p.A {} // 2
+''');
+    ClassElement elementA = importedUnit().getType('A');
+    assertThat(elementA).isExtendedAt('A {} // 2', true);
+  }
+
+  void test_isExtendedBy_ClassDeclaration_Object() {
+    _indexTestUnit('''
+class A {}
+''');
+    ClassElement elementA = findElement('A');
+    ClassElement elementObject = elementA.supertype.element;
+    assertThat(elementObject).isExtendedAt('A {}', true, length: 0);
+  }
+
+  void test_isExtendedBy_ClassTypeAlias() {
+    _indexTestUnit('''
+class A {}
+class B {}
+class C = A with B;
+''');
+    ClassElement elementA = findElement('A');
+    assertThat(elementA)
+      ..isExtendedAt('A with', true)
+      ..isReferencedAt('A with', true);
+  }
+
+  void test_isImplementedBy_ClassDeclaration() {
+    _indexTestUnit('''
+class A {} // 1
+class B implements A {} // 2
+''');
+    ClassElement elementA = findElement('A');
+    assertThat(elementA)
+      ..isImplementedAt('A {} // 2', true)
+      ..isReferencedAt('A {} // 2', true);
+  }
+
+  void test_isImplementedBy_ClassDeclaration_isQualified() {
+    addSource(
+        '/lib.dart',
+        '''
+class A {}
+''');
+    _indexTestUnit('''
+import 'lib.dart' as p;
+class B implements p.A {} // 2
+''');
+    ClassElement elementA = importedUnit().getType('A');
+    assertThat(elementA)
+      ..isImplementedAt('A {} // 2', true)
+      ..isReferencedAt('A {} // 2', true);
+  }
+
+  void test_isImplementedBy_ClassTypeAlias() {
+    _indexTestUnit('''
+class A {} // 1
+class B {} // 2
+class C = Object with A implements B; // 3
+''');
+    ClassElement elementB = findElement('B');
+    assertThat(elementB)
+      ..isImplementedAt('B; // 3', true)
+      ..isReferencedAt('B; // 3', true);
+  }
+
+  void test_isInvokedBy_FieldElement() {
+    _indexTestUnit('''
+class A {
+  var field;
+  main() {
+    this.field(); // q
+    field(); // nq
+  }
+}''');
+    FieldElement field = findElement('field');
+    assertThat(field.getter)
+      ..isInvokedAt('field(); // q', true)
+      ..isInvokedAt('field(); // nq', false);
+  }
+
+  void test_isInvokedBy_FunctionElement() {
+    addSource(
+        '/lib.dart',
+        '''
+library lib;
+foo() {}
+''');
+    _indexTestUnit('''
+import 'lib.dart';
+import 'lib.dart' as pref;
+main() {
+  pref.foo(); // q
+  foo(); // nq
+}''');
+    FunctionElement element = importedUnit().functions[0];
+    assertThat(element)
+      ..isInvokedAt('foo(); // q', true)
+      ..isInvokedAt('foo(); // nq', false);
+  }
+
+  void test_isInvokedBy_MethodElement() {
+    _indexTestUnit('''
+class A {
+  foo() {}
+  main() {
+    this.foo(); // q
+    foo(); // nq
+  }
+}''');
+    Element element = findElement('foo');
+    assertThat(element)
+      ..isInvokedAt('foo(); // q', true)
+      ..isInvokedAt('foo(); // nq', false);
+  }
+
+  void test_isInvokedBy_MethodElement_propagatedType() {
+    _indexTestUnit('''
+class A {
+  foo() {}
+}
+main() {
+  var a = new A();
+  a.foo();
+}
+''');
+    Element element = findElement('foo');
+    assertThat(element).isInvokedAt('foo();', true);
+  }
+
+  void test_isInvokedBy_operator_binary() {
+    _indexTestUnit('''
+class A {
+  operator +(other) => this;
+}
+main(A a) {
+  print(a + 1);
+  a += 2;
+  ++a;
+  a++;
+}
+''');
+    MethodElement element = findElement('+');
+    assertThat(element)
+      ..isInvokedAt('+ 1', true, length: 1)
+      ..isInvokedAt('+= 2', true, length: 2)
+      ..isInvokedAt('++a', true, length: 2)
+      ..isInvokedAt('++;', true, length: 2);
+  }
+
+  void test_isInvokedBy_operator_index() {
+    _indexTestUnit('''
+class A {
+  operator [](i) => null;
+  operator []=(i, v) {}
+}
+main(A a) {
+  print(a[0]);
+  a[1] = 42;
+}
+''');
+    MethodElement readElement = findElement('[]');
+    MethodElement writeElement = findElement('[]=');
+    assertThat(readElement).isInvokedAt('[0]', true, length: 1);
+    assertThat(writeElement).isInvokedAt('[1]', true, length: 1);
+  }
+
+  void test_isInvokedBy_operator_prefix() {
+    _indexTestUnit('''
+class A {
+  A operator ~() => this;
+}
+main(A a) {
+  print(~a);
+}
+''');
+    MethodElement element = findElement('~');
+    assertThat(element).isInvokedAt('~a', true, length: 1);
+  }
+
+  void test_isMixedInBy_ClassDeclaration() {
+    _indexTestUnit('''
+class A {} // 1
+class B extends Object with A {} // 2
+''');
+    ClassElement elementA = findElement('A');
+    assertThat(elementA)
+      ..isMixedInAt('A {} // 2', true)
+      ..isReferencedAt('A {} // 2', true);
+  }
+
+  void test_isMixedInBy_ClassDeclaration_isQualified() {
+    addSource(
+        '/lib.dart',
+        '''
+class A {}
+''');
+    _indexTestUnit('''
+import 'lib.dart' as p;
+class B extends Object with p.A {} // 2
+''');
+    ClassElement elementA = importedUnit().getType('A');
+    assertThat(elementA).isMixedInAt('A {} // 2', true);
+  }
+
+  void test_isMixedInBy_ClassTypeAlias() {
+    _indexTestUnit('''
+class A {} // 1
+class B = Object with A; // 2
+''');
+    ClassElement elementA = findElement('A');
+    assertThat(elementA).isMixedInAt('A; // 2', true);
+  }
+
+  void test_isReferencedBy_ClassElement() {
+    _indexTestUnit('''
+class A {
+  static var field;
+}
+main(A p) {
+  A v;
+  new A(); // 2
+  A.field = 1;
+  print(A.field); // 3
+}
+''');
+    ClassElement element = findElement('A');
+    assertThat(element)
+      ..isReferencedAt('A p) {', false)
+      ..isReferencedAt('A v;', false)
+      ..isReferencedAt('A(); // 2', false)
+      ..isReferencedAt('A.field = 1;', false)
+      ..isReferencedAt('A.field); // 3', false);
+  }
+
+  void test_isReferencedBy_ClassElement_invocation() {
+    verifyNoTestUnitErrors = false;
+    _indexTestUnit('''
+class A {}
+main() {
+  A(); // invalid code, but still a reference
+}''');
+    Element element = findElement('A');
+    assertThat(element).isReferencedAt('A();', false);
+  }
+
+  void test_isReferencedBy_ClassElement_invocation_isQualified() {
+    verifyNoTestUnitErrors = false;
+    addSource(
+        '/lib.dart',
+        '''
+class A {}
+''');
+    _indexTestUnit('''
+import 'lib.dart' as p;
+main() {
+  p.A(); // invalid code, but still a reference
+}''');
+    Element element = importedUnit().getType('A');
+    assertThat(element).isReferencedAt('A();', true);
+  }
+
+  void test_isReferencedBy_ClassTypeAlias() {
+    _indexTestUnit('''
+class A {}
+class B = Object with A;
+main(B p) {
+  B v;
+}
+''');
+    ClassElement element = findElement('B');
+    assertThat(element)
+      ..isReferencedAt('B p) {', false)
+      ..isReferencedAt('B v;', false);
+  }
+
+  void test_isReferencedBy_CompilationUnitElement_export() {
+    addSource(
+        '/lib.dart',
+        '''
+library lib;
+''');
+    _indexTestUnit('''
+export 'lib.dart';
+''');
+    LibraryElement element = testLibraryElement.exports[0].exportedLibrary;
+    assertThat(element)..isReferencedAt("'lib.dart'", true, length: 10);
+  }
+
+  void test_isReferencedBy_CompilationUnitElement_import() {
+    addSource(
+        '/lib.dart',
+        '''
+library lib;
+''');
+    _indexTestUnit('''
+import 'lib.dart';
+''');
+    LibraryElement element = testLibraryElement.imports[0].importedLibrary;
+    assertThat(element)..isReferencedAt("'lib.dart'", true, length: 10);
+  }
+
+  void test_isReferencedBy_CompilationUnitElement_part() {
+    addSource('/my_unit.dart', 'part of my_lib;');
+    _indexTestUnit('''
+library my_lib;
+part 'my_unit.dart';
+''');
+    CompilationUnitElement element = testLibraryElement.parts[0];
+    assertThat(element)..isReferencedAt("'my_unit.dart';", true, length: 14);
+  }
+
+  void test_isReferencedBy_ConstructorElement() {
+    _indexTestUnit('''
+class A implements B {
+  A() {}
+  A.foo() {}
+}
+class B extends A {
+  B() : super(); // 1
+  B.foo() : super.foo(); // 2
+  factory B.bar() = A.foo; // 3
+}
+main() {
+  new A(); // 4
+  new A.foo(); // 5
+}
+''');
+    ClassElement classA = findElement('A');
+    ConstructorElement constA = classA.constructors[0];
+    ConstructorElement constA_foo = classA.constructors[1];
+    // A()
+    assertThat(constA)
+      ..isReferencedAt('(); // 1', true, length: 0)
+      ..isReferencedAt('(); // 4', true, length: 0);
+    // A.foo()
+    assertThat(constA_foo)
+      ..isReferencedAt('.foo(); // 2', true, length: 4)
+      ..isReferencedAt('.foo; // 3', true, length: 4)
+      ..isReferencedAt('.foo(); // 5', true, length: 4);
+  }
+
+  void test_isReferencedBy_ConstructorElement_classTypeAlias() {
+    _indexTestUnit('''
+class M {}
+class A implements B {
+  A() {}
+  A.named() {}
+}
+class B = A with M;
+class C = B with M;
+main() {
+  new B(); // B1
+  new B.named(); // B2
+  new C(); // C1
+  new C.named(); // C2
+}
+''');
+    ClassElement classA = findElement('A');
+    ConstructorElement constA = classA.constructors[0];
+    ConstructorElement constA_named = classA.constructors[1];
+    assertThat(constA)
+      ..isReferencedAt('(); // B1', true, length: 0)
+      ..isReferencedAt('(); // C1', true, length: 0);
+    assertThat(constA_named)
+      ..isReferencedAt('.named(); // B2', true, length: 6)
+      ..isReferencedAt('.named(); // C2', true, length: 6);
+  }
+
+  void test_isReferencedBy_ConstructorElement_classTypeAlias_cycle() {
+    _indexTestUnit('''
+class M {}
+class A = B with M;
+class B = A with M;
+main() {
+  new A();
+  new B();
+}
+''');
+    // No additional validation, but it should not fail with stack overflow.
+  }
+
+  void test_isReferencedBy_ConstructorElement_redirection() {
+    _indexTestUnit('''
+class A {
+  A() : this.bar(); // 1
+  A.foo() : this(); // 2
+  A.bar();
+}
+''');
+    ClassElement classA = findElement('A');
+    ConstructorElement constA = classA.constructors[0];
+    ConstructorElement constA_bar = classA.constructors[2];
+    assertThat(constA).isReferencedAt('(); // 2', true, length: 0);
+    assertThat(constA_bar).isReferencedAt('.bar(); // 1', true, length: 4);
+  }
+
+  void test_isReferencedBy_ConstructorFieldInitializer() {
+    _indexTestUnit('''
+class A {
+  int field;
+  A() : field = 5;
+}
+''');
+    FieldElement element = findElement('field');
+    assertThat(element).isReferencedAt('field = 5', true);
+  }
+
+  void test_isReferencedBy_FieldElement() {
+    _indexTestUnit('''
+class A {
+  var field;
+  A({this.field});
+  m() {
+    field = 1; // nq
+    print(field); // nq
+  }
+}
+main(A a) {
+  a.field = 2; // q
+  print(a.field); // q
+  new A(field: 3);
+}
+''');
+    FieldElement field = findElement('field');
+    PropertyAccessorElement getter = field.getter;
+    PropertyAccessorElement setter = field.setter;
+    // A()
+    assertThat(field)..isReferencedAt('field});', true);
+    // m()
+    assertThat(setter)..isReferencedAt('field = 1; // nq', false);
+    assertThat(getter)..isReferencedAt('field); // nq', false);
+    // main()
+    assertThat(setter)..isReferencedAt('field = 2; // q', true);
+    assertThat(getter)..isReferencedAt('field); // q', true);
+    assertThat(field)..isReferencedAt('field: 3', true);
+  }
+
+  void test_isReferencedBy_FunctionElement() {
+    _indexTestUnit('''
+foo() {}
+main() {
+  print(foo);
+  print(foo());
+}
+''');
+    FunctionElement element = findElement('foo');
+    assertThat(element)
+      ..isReferencedAt('foo);', false)
+      ..isInvokedAt('foo());', false);
+  }
+
+  void test_isReferencedBy_FunctionTypeAliasElement() {
+    _indexTestUnit('''
+typedef A();
+main(A p) {
+}
+''');
+    Element element = findElement('A');
+    assertThat(element)..isReferencedAt('A p) {', false);
+  }
+
+  /**
+   * There was a bug in the AST structure, when single [Comment] was cloned and
+   * assigned to both [FieldDeclaration] and [VariableDeclaration].
+   *
+   * This caused duplicate indexing.
+   * Here we test that the problem is fixed one way or another.
+   */
+  void test_isReferencedBy_identifierInComment() {
+    _indexTestUnit('''
+class A {}
+/// [A] text
+var myVariable = null;
+''');
+    Element element = findElement('A');
+    assertThat(element)..isReferencedAt('A] text', false);
+  }
+
+  void test_isReferencedBy_MethodElement() {
+    _indexTestUnit('''
+class A {
+  method() {}
+  main() {
+    print(this.method); // q
+    print(method); // nq
+  }
+}''');
+    MethodElement element = findElement('method');
+    assertThat(element)
+      ..isReferencedAt('method); // q', true)
+      ..isReferencedAt('method); // nq', false);
+  }
+
+  void test_isReferencedBy_ParameterElement() {
+    _indexTestUnit('''
+foo({var p}) {}
+main() {
+  foo(p: 1);
+}
+''');
+    Element element = findElement('p');
+    assertThat(element)..isReferencedAt('p: 1', true);
+  }
+
+  void test_isReferencedBy_TopLevelVariableElement() {
+    addSource(
+        '/lib.dart',
+        '''
+library lib;
+var V;
+''');
+    _indexTestUnit('''
+import 'lib.dart' show V; // imp
+import 'lib.dart' as pref;
+main() {
+  pref.V = 5; // q
+  print(pref.V); // q
+  V = 5; // nq
+  print(V); // nq
+}''');
+    TopLevelVariableElement variable = importedUnit().topLevelVariables[0];
+    assertThat(variable)..isReferencedAt('V; // imp', true);
+    assertThat(variable.getter)
+      ..isReferencedAt('V); // q', true)
+      ..isReferencedAt('V); // nq', false);
+    assertThat(variable.setter)
+      ..isReferencedAt('V = 5; // q', true)
+      ..isReferencedAt('V = 5; // nq', false);
+  }
+
+  void test_isReferencedBy_typeInVariableList() {
+    _indexTestUnit('''
+class A {}
+A myVariable = null;
+''');
+    Element element = findElement('A');
+    assertThat(element).isReferencedAt('A myVariable', false);
+  }
+
+  void test_usedName_isInvokedBy() {
+    verifyNoTestUnitErrors = false;
+    _indexTestUnit('''
+class C {
+  x() {}
+}
+main(C c) {
+  x(); // nq
+  c.x(); // q
+  y(); // nq
+  c.y(); // q
+}
+''');
+    assertThatName('x')
+      ..isNotInvokedAt('x(); // nq')
+      ..isNotInvokedAt('x(); // q');
+    assertThatName('y')
+      ..isNotInvokedAt('y(); // nq')
+      ..isInvokedAt('y(); // q');
+  }
+
+  void test_usedName_isReferencedBy() {
+    verifyNoTestUnitErrors = false;
+    _indexTestUnit('''
+class C {
+  int x;
+}
+main(C c) {
+  x; // nq
+  c.x; // q
+  y; // nq
+  c.y; // q
+}
+''');
+    assertThatName('x')
+      ..isNotReferencedAt('x; // nq')
+      ..isNotReferencedAt('x; // q');
+    assertThatName('y')
+      ..isNotReferencedAt('y; // nq')
+      ..isReferencedAt('y; // q');
+  }
+
+  void _assertDefinedName(String name, IndexNameKind kind, String search) {
+    int offset = findOffset(search);
+    int nameId = _getStringId(name);
+    for (int i = 0; i < unitIndex.definedNames.length; i++) {
+      if (unitIndex.definedNames[i] == nameId &&
+          unitIndex.definedNameKinds[i] == kind &&
+          unitIndex.definedNameOffsets[i] == offset) {
+        return;
+      }
+    }
+    _failWithIndexDump('Not found $name $kind at $offset');
+  }
+
+  /**
+   * Asserts that [unitIndex] has an item with the expected properties.
+   */
+  void _assertHasRelation(
+      Element element,
+      IndexRelationKind expectedRelationKind,
+      ExpectedLocation expectedLocation) {
+    int elementId = _findElementId(element);
+    for (int i = 0; i < unitIndex.usedElementOffsets.length; i++) {
+      if (unitIndex.usedElements[i] == elementId &&
+          unitIndex.usedElementKinds[i] == expectedRelationKind &&
+          unitIndex.usedElementOffsets[i] == expectedLocation.offset &&
+          unitIndex.usedElementLengths[i] == expectedLocation.length &&
+          unitIndex.usedElementIsQualifiedFlags[i] ==
+              expectedLocation.isQualified) {
+        return;
+      }
+    }
+    _failWithIndexDump(
+        'not found\n$element $expectedRelationKind at $expectedLocation');
+  }
+
+  void _assertUsedName(String name, IndexRelationKind kind,
+      ExpectedLocation expectedLocation, bool isNot) {
+    int nameId = _getStringId(name);
+    for (int i = 0; i < unitIndex.usedNames.length; i++) {
+      if (unitIndex.usedNames[i] == nameId &&
+          unitIndex.usedNameKinds[i] == kind &&
+          unitIndex.usedNameOffsets[i] == expectedLocation.offset) {
+        if (isNot) {
+          _failWithIndexDump('Unexpected $name $kind at $expectedLocation');
+        }
+        return;
+      }
+    }
+    if (isNot) {
+      return;
+    }
+    _failWithIndexDump('Not found $name $kind at $expectedLocation');
+  }
+
+  ExpectedLocation _expectedLocation(String search, bool isQualified,
+      {int length}) {
+    int offset = findOffset(search);
+    if (length == null) {
+      length = getLeadingIdentifierLength(search);
+    }
+    return new ExpectedLocation(testUnitElement, offset, length, isQualified);
+  }
+
+  void _failWithIndexDump(String msg) {
+    String packageIndexJsonString =
+        new JsonEncoder.withIndent('  ').convert(packageIndex.toJson());
+    fail('$msg in\n' + packageIndexJsonString);
+  }
+
+  /**
+   * Return the [element] identifier in [packageIndex] or fail.
+   */
+  int _findElementId(Element element) {
+    int unitId = _getUnitId(element);
+    int offset = element.nameOffset;
+    if (element is LibraryElement || element is CompilationUnitElement) {
+      offset = 0;
+    }
+    IndexSyntheticElementKind kind =
+        PackageIndexAssembler.getIndexElementKind(element);
+    for (int elementId = 0;
+        elementId < packageIndex.elementUnits.length;
+        elementId++) {
+      if (packageIndex.elementUnits[elementId] == unitId &&
+          packageIndex.elementOffsets[elementId] == offset &&
+          packageIndex.elementKinds[elementId] == kind) {
+        return elementId;
+      }
+    }
+    _failWithIndexDump('Element $element is not referenced');
+    return 0;
+  }
+
+  int _getStringId(String str) {
+    int id = packageIndex.strings.indexOf(str);
+    expect(id, isNonNegative);
+    return id;
+  }
+
+  int _getUnitId(Element element) {
+    CompilationUnitElement unitElement =
+        PackageIndexAssembler.getUnitElement(element);
+    int libraryUriId = _getUriId(unitElement.library.source.uri);
+    int unitUriId = _getUriId(unitElement.source.uri);
+    expect(packageIndex.unitLibraryUris,
+        hasLength(packageIndex.unitUnitUris.length));
+    for (int i = 0; i < packageIndex.unitLibraryUris.length; i++) {
+      if (packageIndex.unitLibraryUris[i] == libraryUriId &&
+          packageIndex.unitUnitUris[i] == unitUriId) {
+        return i;
+      }
+    }
+    _failWithIndexDump('Unit $unitElement of $element is not referenced');
+    return -1;
+  }
+
+  int _getUriId(Uri uri) {
+    String str = uri.toString();
+    return _getStringId(str);
+  }
+
+  void _indexTestUnit(String code) {
+    resolveTestUnit(code);
+    PackageIndexAssembler assembler = new PackageIndexAssembler();
+    assembler.index(testUnit);
+    // assemble, write and read
+    PackageIndexBuilder indexBuilder = assembler.assemble();
+    List<int> indexBytes = indexBuilder.toBuffer();
+    packageIndex = new PackageIndex.fromBuffer(indexBytes);
+    // prepare the only unit index
+    expect(packageIndex.units, hasLength(1));
+    unitIndex = packageIndex.units[0];
+    expect(unitIndex.unit, _getUnitId(testUnitElement));
+  }
+}
+
+class _ElementIndexAssert {
+  final PackageIndexAssemblerTest test;
+  final Element element;
+
+  _ElementIndexAssert(this.test, this.element);
+
+  void isExtendedAt(String search, bool isQualified, {int length}) {
+    test._assertHasRelation(element, IndexRelationKind.IS_EXTENDED_BY,
+        test._expectedLocation(search, isQualified, length: length));
+  }
+
+  void isImplementedAt(String search, bool isQualified, {int length}) {
+    test._assertHasRelation(element, IndexRelationKind.IS_IMPLEMENTED_BY,
+        test._expectedLocation(search, isQualified, length: length));
+  }
+
+  void isInvokedAt(String search, bool isQualified, {int length}) {
+    test._assertHasRelation(element, IndexRelationKind.IS_INVOKED_BY,
+        test._expectedLocation(search, isQualified, length: length));
+  }
+
+  void isMixedInAt(String search, bool isQualified, {int length}) {
+    test._assertHasRelation(element, IndexRelationKind.IS_MIXED_IN_BY,
+        test._expectedLocation(search, isQualified, length: length));
+  }
+
+  void isReferencedAt(String search, bool isQualified, {int length}) {
+    test._assertHasRelation(element, IndexRelationKind.IS_REFERENCED_BY,
+        test._expectedLocation(search, isQualified, length: length));
+  }
+}
+
+class _NameIndexAssert {
+  final PackageIndexAssemblerTest test;
+  final String name;
+
+  _NameIndexAssert(this.test, this.name);
+
+  void isInvokedAt(String search, {int length}) {
+    test._assertUsedName(name, IndexRelationKind.IS_INVOKED_BY,
+        test._expectedLocation(search, true, length: length), false);
+  }
+
+  void isNotInvokedAt(String search, {int length}) {
+    test._assertUsedName(name, IndexRelationKind.IS_INVOKED_BY,
+        test._expectedLocation(search, true, length: length), true);
+  }
+
+  void isNotReferencedAt(String search, {int length}) {
+    test._assertUsedName(name, IndexRelationKind.IS_REFERENCED_BY,
+        test._expectedLocation(search, true, length: length), true);
+  }
+
+  void isReferencedAt(String search, {int length}) {
+    test._assertUsedName(name, IndexRelationKind.IS_REFERENCED_BY,
+        test._expectedLocation(search, true, length: length), false);
+  }
+}
diff --git a/pkg/analyzer/test/src/summary/resynthesize_strong_test.dart b/pkg/analyzer/test/src/summary/resynthesize_strong_test.dart
index b6a9258..37c2f4a 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_strong_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_strong_test.dart
@@ -18,5 +18,6 @@
 @reflectiveTest
 class ResynthStrongTest extends ResynthTest {
   @override
-  AnalysisOptionsImpl get options => super.options..strongMode = true;
+  AnalysisOptionsImpl createOptions() =>
+      super.createOptions()..strongMode = true;
 }
diff --git a/pkg/analyzer/test/src/summary/resynthesize_test.dart b/pkg/analyzer/test/src/summary/resynthesize_test.dart
index 8b1e4dd..e163d04 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_test.dart
@@ -42,7 +42,7 @@
   /**
    * Determine the analysis options that should be used for this test.
    */
-  AnalysisOptionsImpl get options =>
+  AnalysisOptionsImpl createOptions() =>
       new AnalysisOptionsImpl()..enableGenericMethods = true;
 
   void addLibrary(String uri) {
@@ -119,6 +119,7 @@
           original.loadLibraryFunction as ExecutableElementImpl,
           '(loadLibraryFunction)');
     }
+    expect(resynthesized.libraryCycle.toSet(), original.libraryCycle.toSet());
   }
 
   /**
@@ -233,6 +234,8 @@
           '$desc.${original.methods[i].name}');
     }
     compareTypes(resynthesized.type, original.type, desc);
+    expect(resynthesized.hasBeenInferred, original.hasBeenInferred,
+        reason: desc);
   }
 
   void compareCompilationUnitElements(CompilationUnitElementImpl resynthesized,
@@ -642,14 +645,17 @@
     }
   }
 
-  void compareExecutableElements(ExecutableElement resynthesized,
-      ExecutableElement original, String desc) {
+  void compareExecutableElements(
+      ExecutableElement resynthesized, ExecutableElement original, String desc,
+      {bool shallow: false}) {
     compareElements(resynthesized, original, desc);
     compareParameterElementLists(
         resynthesized.parameters, original.parameters, desc);
     compareTypes(
         resynthesized.returnType, original.returnType, '$desc return type');
-    compareTypes(resynthesized.type, original.type, desc);
+    if (!shallow) {
+      compareTypes(resynthesized.type, original.type, desc);
+    }
     expect(resynthesized.typeParameters.length, original.typeParameters.length);
     for (int i = 0; i < resynthesized.typeParameters.length; i++) {
       compareTypeParameterElements(
@@ -704,12 +710,13 @@
   }
 
   void compareFunctionElements(
-      FunctionElement resynthesized, FunctionElement original, String desc) {
+      FunctionElement resynthesized, FunctionElement original, String desc,
+      {bool shallow: false}) {
     if (original == null && resynthesized == null) {
       return;
     }
     expect(resynthesized, isNotNull, reason: desc);
-    compareExecutableElements(resynthesized, original, desc);
+    compareExecutableElements(resynthesized, original, desc, shallow: shallow);
     checkPossibleLocalElements(resynthesized, original);
   }
 
@@ -937,6 +944,15 @@
         compareFunctionTypeAliasElements(
             resynthesized.element, original.element, desc);
       }
+      if (original.element.enclosingElement == null &&
+          original.element is FunctionElement) {
+        expect(resynthesized.element, new isInstanceOf<FunctionElement>());
+        expect(resynthesized.element.enclosingElement, isNull, reason: desc);
+        compareFunctionElements(
+            resynthesized.element, original.element, '$desc element',
+            shallow: true);
+        expect(resynthesized.element.type, same(resynthesized));
+      }
       expect(resynthesized.typeArguments.length, original.typeArguments.length,
           reason: desc);
       for (int i = 0; i < resynthesized.typeArguments.length; i++) {
@@ -993,8 +1009,8 @@
     VariableElementImpl resynthesizedActual =
         getActualElement(resynthesized, desc);
     VariableElementImpl originalActual = getActualElement(original, desc);
-    compareFunctionElements(
-        resynthesizedActual.initializer, originalActual.initializer, desc);
+    compareFunctionElements(resynthesizedActual.initializer,
+        originalActual.initializer, '$desc initializer');
     if (originalActual is ConstVariableElement) {
       Element oEnclosing = original.enclosingElement;
       if (oEnclosing is ClassElement && oEnclosing.isEnum) {
@@ -1072,7 +1088,7 @@
         analysisContext.sourceFactory,
         unlinkedSummaries,
         linkedSummaries,
-        options.strongMode);
+        createOptions().strongMode);
   }
 
   fail_library_hasExtUri() {
@@ -1117,7 +1133,7 @@
   @override
   void setUp() {
     super.setUp();
-    resetWithOptions(options);
+    resetWithOptions(createOptions());
   }
 
   test_class_abstract() {
@@ -2498,6 +2514,11 @@
   }
 
   test_core() {
+    if (createOptions().strongMode) {
+      // The fake `dart:core` library is always in spec mode, so don't bother
+      // trying to check that it resynthesizes properly; it won't.
+      return;
+    }
     String uri = 'dart:core';
     LibraryElementImpl original =
         resolve2(analysisContext2.sourceFactory.forUri(uri));
@@ -2756,12 +2777,12 @@
   }
 
   test_function_type_parameter() {
-    resetWithOptions(new AnalysisOptionsImpl()..enableGenericMethods = true);
+    resetWithOptions(createOptions()..enableGenericMethods = true);
     checkLibrary('T f<T, U>(U u) => null;');
   }
 
   test_function_type_parameter_with_function_typed_parameter() {
-    resetWithOptions(new AnalysisOptionsImpl()..enableGenericMethods = true);
+    resetWithOptions(createOptions()..enableGenericMethods = true);
     checkLibrary('void f<T, U>(T x(U u)) {}');
   }
 
@@ -2770,7 +2791,7 @@
   }
 
   test_generic_gClass_gMethodStatic() {
-    resetWithOptions(new AnalysisOptionsImpl()..enableGenericMethods = true);
+    resetWithOptions(createOptions()..enableGenericMethods = true);
     checkLibrary('''
 class C<T, U> {
   static void m<V, W>(V v, W w) {
@@ -2970,7 +2991,7 @@
   }
 
   test_inferred_function_type_in_generic_closure() {
-    if (!options.strongMode) {
+    if (!createOptions().strongMode) {
       // The test below uses generic comment syntax because proper generic
       // method syntax doesn't support generic closures.  So it can only run in
       // strong mode.
@@ -2989,7 +3010,7 @@
   }
 
   test_inferred_generic_function_type_in_generic_closure() {
-    if (!options.strongMode) {
+    if (!createOptions().strongMode) {
       // The test below uses generic comment syntax because proper generic
       // method syntax doesn't support generic closures.  So it can only run in
       // strong mode.
@@ -3445,17 +3466,17 @@
   }
 
   test_method_type_parameter() {
-    resetWithOptions(new AnalysisOptionsImpl()..enableGenericMethods = true);
+    resetWithOptions(createOptions()..enableGenericMethods = true);
     checkLibrary('class C { T f<T, U>(U u) => null; }');
   }
 
   test_method_type_parameter_in_generic_class() {
-    resetWithOptions(new AnalysisOptionsImpl()..enableGenericMethods = true);
+    resetWithOptions(createOptions()..enableGenericMethods = true);
     checkLibrary('class C<T, U> { V f<V, W>(T t, U u, W w) => null; }');
   }
 
   test_method_type_parameter_with_function_typed_parameter() {
-    resetWithOptions(new AnalysisOptionsImpl()..enableGenericMethods = true);
+    resetWithOptions(createOptions()..enableGenericMethods = true);
     checkLibrary('class C { void f<T, U>(T x(U u)) {} }');
   }
 
@@ -3632,6 +3653,70 @@
     checkLibrary('void set x(int value) {} set y(value) {}');
   }
 
+  test_syntheticFunctionType_genericClosure() {
+    if (!createOptions().strongMode) {
+      // The test below uses generic comment syntax because proper generic
+      // method syntax doesn't support generic closures.  So it can only run in
+      // strong mode.
+      // TODO(paulberry): once proper generic method syntax supports generic
+      // closures, rewrite the test below without using generic comment syntax,
+      // and remove this hack.  See dartbug.com/25819
+      return;
+    }
+    checkLibrary('''
+final v = f() ? /*<T>*/(T t) => 0 : /*<T>*/(T t) => 1;
+bool f() => true;
+''');
+  }
+
+  test_syntheticFunctionType_genericClosure_inGenericFunction() {
+    if (!createOptions().strongMode) {
+      // The test below uses generic comment syntax because proper generic
+      // method syntax doesn't support generic closures.  So it can only run in
+      // strong mode.
+      // TODO(paulberry): once proper generic method syntax supports generic
+      // closures, rewrite the test below without using generic comment syntax,
+      // and remove this hack.  See dartbug.com/25819
+      return;
+    }
+    checkLibrary('''
+void f<T, U>(bool b) {
+  final v = b ? /*<V>*/(T t, U u, V v) => 0 : /*<V>*/(T t, U u, V v) => 1;
+}
+''');
+  }
+
+  test_syntheticFunctionType_inGenericClass() {
+    checkLibrary('''
+class C<T, U> {
+  var v = f() ? (T t, U u) => 0 : (T t, U u) => 1;
+}
+bool f() => false;
+''');
+  }
+
+  test_syntheticFunctionType_inGenericFunction() {
+    checkLibrary('''
+void f<T, U>(bool b) {
+  var v = b ? (T t, U u) => 0 : (T t, U u) => 1;
+}
+''');
+  }
+
+  test_syntheticFunctionType_noArguments() {
+    checkLibrary('''
+final v = f() ? () => 0 : () => 1;
+bool f() => true;
+''');
+  }
+
+  test_syntheticFunctionType_withArguments() {
+    checkLibrary('''
+final v = f() ? (int x, String y) => 0 : (int x, String y) => 1;
+bool f() => true;
+''');
+  }
+
   test_type_arguments_explicit_dynamic_dynamic() {
     checkLibrary('Map<dynamic, dynamic> m;');
   }
@@ -3893,7 +3978,7 @@
   }
 
   test_variable_propagatedType_final_dep_inLib() {
-    addNamedSource('/a.dart', 'final a = 1;');
+    addLibrarySource('/a.dart', 'final a = 1;');
     checkLibrary('import "a.dart"; final b = a / 2;');
   }
 
@@ -3908,8 +3993,8 @@
 
   test_variable_propagatedType_implicit_dep() {
     // The propagated type is defined in a library that is not imported.
-    addNamedSource('/a.dart', 'class C {}');
-    addNamedSource('/b.dart', 'import "a.dart"; C f() => null;');
+    addLibrarySource('/a.dart', 'class C {}');
+    addLibrarySource('/b.dart', 'import "a.dart"; C f() => null;');
     checkLibrary('import "b.dart"; final x = f();');
   }
 
diff --git a/pkg/analyzer/test/src/summary/summary_common.dart b/pkg/analyzer/test/src/summary/summary_common.dart
index 6356d47..9427cd6 100644
--- a/pkg/analyzer/test/src/summary/summary_common.dart
+++ b/pkg/analyzer/test/src/summary/summary_common.dart
@@ -6525,6 +6525,130 @@
     expect(unlinkedUnits[1].variables[0].propagatedTypeSlot, 1);
   }
 
+  test_syntheticFunctionType_genericClosure() {
+    if (skipFullyLinkedData) {
+      return;
+    }
+    if (!strongMode) {
+      // The test below uses generic comment syntax because proper generic
+      // method syntax doesn't support generic closures.  So it can only run in
+      // strong mode.
+      // TODO(paulberry): once proper generic method syntax supports generic
+      // closures, rewrite the test below without using generic comment syntax,
+      // and remove this hack.  See dartbug.com/25819
+      return;
+    }
+    UnlinkedVariable variable = serializeVariableText('''
+final v = f() ? /*<T>*/(T t) => 0 : /*<T>*/(T t) => 1;
+bool f() => true;
+''');
+    // The inferred type of `v` is currently `(Object) -> int` due to
+    // dartbug.com/25802.  TODO(paulberry): fix this test when the bug is fixed.
+    EntityRef inferredType = getTypeRefForSlot(variable.inferredTypeSlot);
+    checkLinkedTypeRef(
+        inferredType.syntheticReturnType, 'dart:core', 'dart:core', 'int');
+    expect(inferredType.syntheticParams, hasLength(1));
+    checkLinkedTypeRef(inferredType.syntheticParams[0].type, 'dart:core',
+        'dart:core', 'Object');
+  }
+
+  test_syntheticFunctionType_genericClosure_inGenericFunction() {
+    if (skipFullyLinkedData) {
+      return;
+    }
+    if (!strongMode) {
+      // The test below uses generic comment syntax because proper generic
+      // method syntax doesn't support generic closures.  So it can only run in
+      // strong mode.
+      // TODO(paulberry): once proper generic method syntax supports generic
+      // closures, rewrite the test below without using generic comment syntax,
+      // and remove this hack.  See dartbug.com/25819
+      return;
+    }
+    UnlinkedVariable variable = serializeExecutableText('''
+void f<T, U>(bool b) {
+  final v = b ? /*<V>*/(T t, U u, V v) => 0 : /*<V>*/(T t, U u, V v) => 1;
+}
+''').localVariables[0];
+    // The inferred type of `v` is currently `(T, U, Object) -> int` due to
+    // dartbug.com/25802.  TODO(paulberry): fix this test when the bug is fixed.
+    EntityRef inferredType = getTypeRefForSlot(variable.inferredTypeSlot);
+    checkLinkedTypeRef(
+        inferredType.syntheticReturnType, 'dart:core', 'dart:core', 'int');
+    expect(inferredType.syntheticParams, hasLength(3));
+    checkParamTypeRef(inferredType.syntheticParams[0].type, 2);
+    checkParamTypeRef(inferredType.syntheticParams[1].type, 1);
+    checkLinkedTypeRef(inferredType.syntheticParams[2].type, 'dart:core',
+        'dart:core', 'Object');
+  }
+
+  test_syntheticFunctionType_inGenericClass() {
+    if (skipFullyLinkedData) {
+      return;
+    }
+    UnlinkedVariable variable = serializeClassText('''
+class C<T, U> {
+  var v = f() ? (T t, U u) => 0 : (T t, U u) => 1;
+}
+bool f() => false;
+''').fields[0];
+    EntityRef inferredType =
+        getTypeRefForSlot(variable.initializer.inferredReturnTypeSlot);
+    checkLinkedTypeRef(
+        inferredType.syntheticReturnType, 'dart:core', 'dart:core', 'int');
+    checkParamTypeRef(inferredType.syntheticParams[0].type, 2);
+    checkParamTypeRef(inferredType.syntheticParams[1].type, 1);
+  }
+
+  test_syntheticFunctionType_inGenericFunction() {
+    if (skipFullyLinkedData) {
+      return;
+    }
+    UnlinkedVariable variable = serializeExecutableText('''
+void f<T, U>(bool b) {
+  var v = b ? (T t, U u) => 0 : (T t, U u) => 1;
+}
+''').localVariables[0];
+    EntityRef inferredType =
+        getTypeRefForSlot(variable.initializer.inferredReturnTypeSlot);
+    checkLinkedTypeRef(
+        inferredType.syntheticReturnType, 'dart:core', 'dart:core', 'int');
+    checkParamTypeRef(inferredType.syntheticParams[0].type, 2);
+    checkParamTypeRef(inferredType.syntheticParams[1].type, 1);
+  }
+
+  test_syntheticFunctionType_noArguments() {
+    if (skipFullyLinkedData) {
+      return;
+    }
+    UnlinkedVariable variable = serializeVariableText('''
+final v = f() ? () => 0 : () => 1;
+bool f() => true;
+''');
+    EntityRef propagatedType = getTypeRefForSlot(variable.propagatedTypeSlot);
+    checkLinkedTypeRef(
+        propagatedType.syntheticReturnType, 'dart:core', 'dart:core', 'int');
+    expect(propagatedType.syntheticParams, isEmpty);
+  }
+
+  test_syntheticFunctionType_withArguments() {
+    if (skipFullyLinkedData) {
+      return;
+    }
+    UnlinkedVariable variable = serializeVariableText('''
+final v = f() ? (int x, String y) => 0 : (int x, String y) => 1;
+bool f() => true;
+''');
+    EntityRef propagatedType = getTypeRefForSlot(variable.propagatedTypeSlot);
+    checkTypeRef(
+        propagatedType.syntheticReturnType, 'dart:core', 'dart:core', 'int');
+    expect(propagatedType.syntheticParams, hasLength(2));
+    checkTypeRef(propagatedType.syntheticParams[0].type, 'dart:core',
+        'dart:core', 'int');
+    checkTypeRef(propagatedType.syntheticParams[1].type, 'dart:core',
+        'dart:core', 'String');
+  }
+
   test_type_arguments_explicit() {
     EntityRef typeRef = serializeTypeText('List<int>');
     checkTypeRef(typeRef, 'dart:core', 'dart:core', 'List',
@@ -7076,8 +7200,7 @@
   }
 
   test_variable_initializer_withLocals() {
-    String text =
-        'var v = <dynamic, dynamic>{"1": () { f1() {} var v1; }, '
+    String text = 'var v = <dynamic, dynamic>{"1": () { f1() {} var v1; }, '
         '"2": () { f2() {} var v2; }};';
     UnlinkedVariable variable = serializeVariableText(text);
     UnlinkedExecutable initializer = variable.initializer;
diff --git a/pkg/analyzer/test/src/summary/test_all.dart b/pkg/analyzer/test/src/summary/test_all.dart
index d24342f..fe80a5a 100644
--- a/pkg/analyzer/test/src/summary/test_all.dart
+++ b/pkg/analyzer/test/src/summary/test_all.dart
@@ -8,6 +8,7 @@
 
 import '../../utils.dart';
 import 'flat_buffers_test.dart' as flat_buffers_test;
+import 'index_unit_test.dart' as index_unit_test;
 import 'name_filter_test.dart' as name_filter_test;
 import 'prelinker_test.dart' as prelinker_test;
 import 'resynthesize_strong_test.dart' as resynthesize_strong_test;
@@ -21,6 +22,7 @@
   initializeTestEnvironment();
   group('summary tests', () {
     flat_buffers_test.main();
+    index_unit_test.main();
     name_filter_test.main();
     prelinker_test.main();
     resynthesize_strong_test.main();
diff --git a/pkg/analyzer/test/src/task/options_test.dart b/pkg/analyzer/test/src/task/options_test.dart
index ebdca70..105ed8b 100644
--- a/pkg/analyzer/test/src/task/options_test.dart
+++ b/pkg/analyzer/test/src/task/options_test.dart
@@ -77,6 +77,16 @@
     expect(analysisOptions.enableGenericMethods, true);
   }
 
+  test_configure_enableConditionalDirectives() {
+    expect(analysisOptions.enableConditionalDirectives, false);
+    configureContext('''
+analyzer:
+  language:
+    enableConditionalDirectives: true
+''');
+    expect(analysisOptions.enableConditionalDirectives, true);
+  }
+
   test_configure_enableSuperMixins() {
     configureContext('''
 analyzer:
diff --git a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
index ba964d8..4bfe3521 100644
--- a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
+++ b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
@@ -1903,8 +1903,10 @@
       void foo(int f(Object _)) {}
 
       main() {
-        var f = (x) => null;
-        f = (x) => 'hello';
+        var f = (Object x) => null;
+        String y = /*info:DYNAMIC_CAST*/f(42);
+
+        f = /*info:INFERRED_TYPE_CLOSURE*/(x) => 'hello';
 
         var g = null;
         g = 'hello';
@@ -1960,4 +1962,233 @@
 }
     ''');
   });
+
+
+  group('block bodied lambdas', () {
+    // Original feature request: https://github.com/dart-lang/sdk/issues/25487
+
+    test('basic', () {
+      checkFile(r'''
+        test1() {
+          List<int> o;
+          var y = o.map(/*info:INFERRED_TYPE_CLOSURE,info:INFERRED_TYPE_CLOSURE*/(x) { return x + 1; });
+          Iterable<int> z = y;
+        }
+      ''');
+    });
+
+    test('no return', () {
+      var mainUnit = checkFile(r'''
+        test1() {
+          List<int> o;
+          var y = o.map(/*info:INFERRED_TYPE_CLOSURE*/(x) { });
+          Iterable<int> z = /*warning:DOWN_CAST_COMPOSITE*/y;
+        }
+      ''');
+      var f = mainUnit.element.functions[0].localVariables[1];
+      expect(f.type.toString(), 'Iterable<dynamic>');
+    });
+
+    test('LUB', () {
+      checkFile(r'''
+        import 'dart:math' show Random;
+        test2() {
+          List<num> o;
+          var y = o.map(/*info:INFERRED_TYPE_CLOSURE,info:INFERRED_TYPE_CLOSURE*/(x) {
+            if (new Random().nextBool()) {
+              return x.toInt() + 1;
+            } else {
+              return x.toDouble();
+            }
+          });
+          Iterable<num> w = y;
+          Iterable<int> z = /*info:ASSIGNMENT_CAST*/y;
+        }
+      ''');
+    });
+
+    group('does not infer bottom', () {
+      test('sync', () {
+        var mainUnit = checkFile(r'''
+          var h = null;
+          void foo(int f(Object _)) {}
+
+          main() {
+            var f = (Object x) { return null; };
+            String y = /*info:DYNAMIC_CAST*/f(42);
+
+            f = /*info:INFERRED_TYPE_CLOSURE*/(x) => 'hello';
+
+            foo(/*info:INFERRED_TYPE_CLOSURE,info:INFERRED_TYPE_CLOSURE*/(x) { return null; });
+            foo(/*info:INFERRED_TYPE_CLOSURE,info:INFERRED_TYPE_CLOSURE*/(x) { throw "not implemented"; });
+          }
+        ''');
+
+        var f = mainUnit.element.functions[1].localVariables[0];
+        expect(f.type.toString(), '(Object) → dynamic');
+      });
+
+      test('sync*', () {
+        var mainUnit = checkFile(r'''
+          main() {
+            var f = () sync* { yield null; };
+            Iterable y = f();
+            Iterable<String> z = /*warning:DOWN_CAST_COMPOSITE*/f();
+            String s = /*info:DYNAMIC_CAST*/f().first;
+          }
+        ''');
+
+        var f = mainUnit.element.functions[0].localVariables[0];
+        expect(f.type.toString(), '() → Iterable<dynamic>');
+      });
+
+      test('async', () {
+        var mainUnit = checkFile(r'''
+          import 'dart:async';
+          main() async {
+            var f = () async { return null; };
+            Future y = f();
+            Future<String> z = /*warning:DOWN_CAST_COMPOSITE*/f();
+            String s = /*info:DYNAMIC_CAST*/await f();
+          }
+        ''');
+
+        var f = mainUnit.element.functions[0].localVariables[0];
+        expect(f.type.toString(), '() → Future<dynamic>');
+      });
+
+      test('async*', () {
+        var mainUnit = checkFile(r'''
+          import 'dart:async';
+          main() async {
+            var f = () async* { yield null; };
+            Stream y = f();
+            Stream<String> z = /*warning:DOWN_CAST_COMPOSITE*/f();
+            String s = /*info:DYNAMIC_CAST*/await f().first;
+          }
+        ''');
+
+        var f = mainUnit.element.functions[0].localVariables[0];
+        expect(f.type.toString(), '() → Stream<dynamic>');
+      });
+    });
+
+    group('async', () {
+      test('all returns are values', () {
+        var mainUnit = checkFile(r'''
+          import 'dart:async';
+          import 'dart:math' show Random;
+          main() {
+            var f = /*info:INFERRED_TYPE_CLOSURE*/() async {
+              if (new Random().nextBool()) {
+                return 1;
+              } else {
+                return 2.0;
+              }
+            };
+            Future<num> g = f();
+            Future<int> h = /*info:ASSIGNMENT_CAST*/f();
+          }
+        ''');
+        var f = mainUnit.element.functions[0].localVariables[0];
+        expect(f.type.toString(), '() → Future<num>');
+      });
+
+      test('all returns are futures', () {
+        var mainUnit = checkFile(r'''
+          import 'dart:async';
+          import 'dart:math' show Random;
+          main() {
+            var f = /*info:INFERRED_TYPE_CLOSURE*/() async {
+              if (new Random().nextBool()) {
+                return new Future<int>.value(1);
+              } else {
+                return new Future<double>.value(2.0);
+              }
+            };
+            Future<num> g = f();
+            Future<int> h = /*info:ASSIGNMENT_CAST*/f();
+          }
+        ''');
+        var f = mainUnit.element.functions[0].localVariables[0];
+        expect(f.type.toString(), '() → Future<num>');
+      });
+
+      test('mix of values and futures', () {
+        var mainUnit = checkFile(r'''
+          import 'dart:async';
+          import 'dart:math' show Random;
+          main() {
+            var f = /*info:INFERRED_TYPE_CLOSURE*/() async {
+              if (new Random().nextBool()) {
+                return new Future<int>.value(1);
+              } else {
+                return 2.0;
+              }
+            };
+            Future<num> g = f();
+            Future<int> h = /*info:ASSIGNMENT_CAST*/f();
+          }
+        ''');
+        var f = mainUnit.element.functions[0].localVariables[0];
+        expect(f.type.toString(), '() → Future<num>');
+      });
+    });
+
+    test('sync*', () {
+      var mainUnit = checkFile(r'''
+        main() {
+          var f = /*info:INFERRED_TYPE_CLOSURE*/() sync* {
+            yield 1;
+            yield* [3, 4.0];
+          };
+          Iterable<num> g = f();
+          Iterable<int> h = /*info:ASSIGNMENT_CAST*/f();
+        }
+      ''');
+      var f = mainUnit.element.functions[0].localVariables[0];
+      expect(f.type.toString(), '() → Iterable<num>');
+    });
+
+    test('async*', () {
+      var mainUnit = checkFile(r'''
+        import 'dart:async';
+        main() {
+          var f = /*info:INFERRED_TYPE_CLOSURE*/() async* {
+            yield 1;
+            Stream<double> s;
+            yield* s;
+          };
+          Stream<num> g = f();
+          Stream<int> h = /*info:ASSIGNMENT_CAST*/f();
+        }
+      ''');
+      var f = mainUnit.element.functions[0].localVariables[0];
+      expect(f.type.toString(), '() → Stream<num>');
+    });
+
+    test('downwards incompatible with upwards inference', () {
+      var mainUnit = checkFile(r'''
+        main() {
+          String f() => null;
+          var g = f;
+          g = /*info:INFERRED_TYPE_CLOSURE*/() { return /*severe:STATIC_TYPE_ERROR*/1; };
+        }
+      ''');
+      var f = mainUnit.element.functions[0].localVariables[0];
+      expect(f.type.toString(), '() → String');
+    });
+
+    test('nested lambdas', () {
+      var mainUnit = checkFile(r'''
+        main() {
+          var f = /*info:INFERRED_TYPE_CLOSURE*/() {
+            return /*info:INFERRED_TYPE_CLOSURE*/(int x) { return 2.0 * x; };
+          };
+        }
+      ''');
+      var f = mainUnit.element.functions[0].localVariables[0];
+      expect(f.type.toString(), '() → (int) → num');
+    });
+  });
 }
diff --git a/pkg/analyzer/test/src/task/strong/strong_test_helper.dart b/pkg/analyzer/test/src/task/strong/strong_test_helper.dart
index 19ed5b3..e04fb30 100644
--- a/pkg/analyzer/test/src/task/strong/strong_test_helper.dart
+++ b/pkg/analyzer/test/src/task/strong/strong_test_helper.dart
@@ -52,7 +52,9 @@
 ///
 /// See [addFile] for more information about how to encode expectations in
 /// the file text.
-void check() {
+///
+/// Returns the main resolved library. This can be used for further checks.
+CompilationUnit check() {
   _checkCalled = true;
 
   expect(files.getFile('/main.dart').exists, true,
@@ -93,12 +95,16 @@
       _expectErrors(resolved, errors);
     }
   }
+
+  return initialLibrary;
 }
 
 /// Adds a file using [addFile] and calls [check].
-void checkFile(String content) {
+///
+/// Also returns the resolved compilation unit.
+CompilationUnit checkFile(String content) {
   addFile(content);
-  check();
+  return check();
 }
 
 SourceSpanWithContext _createSpanHelper(
diff --git a/pkg/analyzer/tool/summary/build_sdk_summaries.dart b/pkg/analyzer/tool/summary/build_sdk_summaries.dart
index 176f7c6..29f49db 100644
--- a/pkg/analyzer/tool/summary/build_sdk_summaries.dart
+++ b/pkg/analyzer/tool/summary/build_sdk_summaries.dart
@@ -1,6 +1,6 @@
-import 'dart:convert';
 import 'dart:io';
 
+import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/java_io.dart';
@@ -8,8 +8,8 @@
 import 'package:analyzer/src/generated/sdk_io.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/summary/format.dart';
+import 'package:analyzer/src/summary/index_unit.dart';
 import 'package:analyzer/src/summary/summarize_elements.dart';
-import 'package:crypto/crypto.dart';
 import 'package:path/path.dart';
 
 main(List<String> args) {
@@ -71,11 +71,8 @@
   AnalysisContext context;
   final Set<Source> processedSources = new Set<Source>();
 
-  final List<String> linkedLibraryUris = <String>[];
-  final List<LinkedLibraryBuilder> linkedLibraries = <LinkedLibraryBuilder>[];
-  final List<String> unlinkedUnitUris = <String>[];
-  final List<UnlinkedUnitBuilder> unlinkedUnits = <UnlinkedUnitBuilder>[];
-  final List<String> unlinkedUnitHashes = <String>[];
+  final PackageBundleAssembler bundleAssembler = new PackageBundleAssembler();
+  final PackageIndexAssembler indexAssembler = new PackageIndexAssembler();
 
   _Builder(this.sdkPath, this.outputDirectoryPath, this.strongMode);
 
@@ -83,7 +80,8 @@
    * Build a strong or spec mode summary for the Dart SDK at [sdkPath].
    */
   void build() {
-    print('Generating ${strongMode ? 'strong' : 'spec'} mode summary.');
+    String modeName = strongMode ? 'strong' : 'spec';
+    print('Generating $modeName mode summary and index.');
     Stopwatch sw = new Stopwatch()..start();
     //
     // Prepare SDK.
@@ -111,16 +109,21 @@
     //
     // Write the whole SDK bundle.
     //
-    PackageBundleBuilder sdkBundle = new PackageBundleBuilder(
-        linkedLibraryUris: linkedLibraryUris,
-        linkedLibraries: linkedLibraries,
-        unlinkedUnitUris: unlinkedUnitUris,
-        unlinkedUnits: unlinkedUnits,
-        unlinkedUnitHashes: unlinkedUnitHashes);
-    String outputFilePath =
-        join(outputDirectoryPath, strongMode ? 'strong.sum' : 'spec.sum');
-    File file = new File(outputFilePath);
-    file.writeAsBytesSync(sdkBundle.toBuffer(), mode: FileMode.WRITE_ONLY);
+    {
+      PackageBundleBuilder bundle = bundleAssembler.assemble();
+      String outputPath = join(outputDirectoryPath, '$modeName.sum');
+      File file = new File(outputPath);
+      file.writeAsBytesSync(bundle.toBuffer(), mode: FileMode.WRITE_ONLY);
+    }
+    //
+    // Write the whole SDK index.
+    //
+    {
+      PackageIndexBuilder index = indexAssembler.assemble();
+      String outputPath = join(outputDirectoryPath, '$modeName.index');
+      File file = new File(outputPath);
+      file.writeAsBytesSync(index.toBuffer(), mode: FileMode.WRITE_ONLY);
+    }
     //
     // Done.
     //
@@ -128,15 +131,6 @@
   }
 
   /**
-   * Compute a hash of the given file contents.
-   */
-  String _hash(String contents) {
-    MD5 md5 = new MD5();
-    md5.add(UTF8.encode(contents));
-    return CryptoUtils.bytesToHex(md5.close());
-  }
-
-  /**
    * Serialize the library with the given [source] and all its direct or
    * indirect imports and exports.
    */
@@ -145,24 +139,15 @@
       return;
     }
     LibraryElement element = context.computeLibraryElement(source);
-    _serializeSingleLibrary(element);
+    bundleAssembler.serializeLibraryElement(element);
     element.importedLibraries.forEach((e) => _serializeLibrary(e.source));
     element.exportedLibraries.forEach((e) => _serializeLibrary(e.source));
-  }
-
-  /**
-   * Serialize the library with the given [element].
-   */
-  void _serializeSingleLibrary(LibraryElement element) {
-    String uri = element.source.uri.toString();
-    LibrarySerializationResult libraryResult =
-        serializeLibrary(element, context.typeProvider, strongMode);
-    linkedLibraryUris.add(uri);
-    linkedLibraries.add(libraryResult.linked);
-    unlinkedUnitUris.addAll(libraryResult.unitUris);
-    unlinkedUnits.addAll(libraryResult.unlinkedUnits);
-    for (Source source in libraryResult.unitSources) {
-      unlinkedUnitHashes.add(_hash(source.contents.data));
+    // Index every unit of the library.
+    for (CompilationUnitElement unitElement in element.units) {
+      Source unitSource = unitElement.source;
+      CompilationUnit unit =
+          context.resolveCompilationUnit2(unitSource, source);
+      indexAssembler.index(unit);
     }
   }
 }
diff --git a/pkg/analyzer/tool/summary/check_test.dart b/pkg/analyzer/tool/summary/check_test.dart
index ac5f7bb..156dc19 100644
--- a/pkg/analyzer/tool/summary/check_test.dart
+++ b/pkg/analyzer/tool/summary/check_test.dart
@@ -19,5 +19,5 @@
   String script = Platform.script.toFilePath(windows: Platform.isWindows);
   String pkgPath = normalize(join(dirname(script), '..', '..'));
   GeneratedContent.checkAll(
-      pkgPath, 'tool/summary/generate.dart', <GeneratedContent>[target]);
+      pkgPath, 'tool/summary/generate.dart', allTargets);
 }
diff --git a/pkg/analyzer/tool/summary/generate.dart b/pkg/analyzer/tool/summary/generate.dart
index 9d5fcb6..cfa14a0 100644
--- a/pkg/analyzer/tool/summary/generate.dart
+++ b/pkg/analyzer/tool/summary/generate.dart
@@ -38,33 +38,34 @@
 main() {
   String script = Platform.script.toFilePath(windows: Platform.isWindows);
   String pkgPath = normalize(join(dirname(script), '..', '..'));
-  GeneratedContent.generateAll(pkgPath, <GeneratedContent>[target]);
+  GeneratedContent.generateAll(pkgPath, allTargets);
 }
 
-final GeneratedFile target =
+final List<GeneratedContent> allTargets = <GeneratedContent>[
+  formatTarget,
+  schemaTarget
+];
+
+final GeneratedFile formatTarget =
     new GeneratedFile('lib/src/summary/format.dart', (String pkgPath) {
-  // Parse the input "IDL" file and pass it to the [_CodeGenerator].
-  PhysicalResourceProvider provider = new PhysicalResourceProvider(
-      PhysicalResourceProvider.NORMALIZE_EOL_ALWAYS);
-  String idlPath = join(pkgPath, 'lib', 'src', 'summary', 'idl.dart');
-  File idlFile = provider.getFile(idlPath);
-  Source idlSource = provider.getFile(idlPath).createSource();
-  String idlText = idlFile.readAsStringSync();
-  BooleanErrorListener errorListener = new BooleanErrorListener();
-  CharacterReader idlReader = new CharSequenceReader(idlText);
-  Scanner scanner = new Scanner(idlSource, idlReader, errorListener);
-  Token tokenStream = scanner.tokenize();
-  LineInfo lineInfo = new LineInfo(scanner.lineStarts);
-  Parser parser = new Parser(idlSource, new BooleanErrorListener());
-  CompilationUnit idlParsed = parser.parseCompilationUnit(tokenStream);
-  _CodeGenerator codeGenerator = new _CodeGenerator();
-  codeGenerator.processCompilationUnit(lineInfo, idlParsed);
+  _CodeGenerator codeGenerator = new _CodeGenerator(pkgPath);
+  codeGenerator.generateFormatCode();
+  return codeGenerator._outBuffer.toString();
+});
+
+final GeneratedFile schemaTarget =
+    new GeneratedFile('lib/src/summary/format.fbs', (String pkgPath) {
+  _CodeGenerator codeGenerator = new _CodeGenerator(pkgPath);
+  codeGenerator.generateFlatBufferSchema();
   return codeGenerator._outBuffer.toString();
 });
 
 typedef String _StringToString(String s);
 
 class _CodeGenerator {
+  static const String _throwDeprecated =
+      "throw new UnimplementedError('attempt to access deprecated field')";
+
   /**
    * Buffer in which generated code is accumulated.
    */
@@ -80,12 +81,43 @@
    */
   idlModel.Idl _idl;
 
+  _CodeGenerator(String pkgPath) {
+    // Parse the input "IDL" file.
+    PhysicalResourceProvider provider = new PhysicalResourceProvider(
+        PhysicalResourceProvider.NORMALIZE_EOL_ALWAYS);
+    String idlPath = join(pkgPath, 'lib', 'src', 'summary', 'idl.dart');
+    File idlFile = provider.getFile(idlPath);
+    Source idlSource = provider.getFile(idlPath).createSource();
+    String idlText = idlFile.readAsStringSync();
+    BooleanErrorListener errorListener = new BooleanErrorListener();
+    CharacterReader idlReader = new CharSequenceReader(idlText);
+    Scanner scanner = new Scanner(idlSource, idlReader, errorListener);
+    Token tokenStream = scanner.tokenize();
+    LineInfo lineInfo = new LineInfo(scanner.lineStarts);
+    Parser parser = new Parser(idlSource, new BooleanErrorListener());
+    CompilationUnit idlParsed = parser.parseCompilationUnit(tokenStream);
+    // Extract a description of the IDL and make sure it is valid.
+    extractIdl(lineInfo, idlParsed);
+    checkIdl();
+  }
+
   /**
    * Perform basic sanity checking of the IDL (over and above that done by
    * [extractIdl]).
    */
   void checkIdl() {
     _idl.classes.forEach((String name, idlModel.ClassDeclaration cls) {
+      if (cls.fileIdentifier != null) {
+        if (cls.fileIdentifier.length != 4) {
+          throw new Exception('$name: file identifier must be 4 characters');
+        }
+        for (int i = 0; i < cls.fileIdentifier.length; i++) {
+          if (cls.fileIdentifier.codeUnitAt(i) >= 256) {
+            throw new Exception(
+                '$name: file identifier must be encodable as Latin-1');
+          }
+        }
+      }
       Map<int, String> idsUsed = <int, String>{};
       for (idlModel.FieldDeclaration field in cls.fields) {
         String fieldName = field.name;
@@ -95,6 +127,8 @@
             // List of classes is ok
           } else if (_idl.enums.containsKey(type.typeName)) {
             // List of enums is ok
+          } else if (type.typeName == 'bool') {
+            // List of booleans is ok
           } else if (type.typeName == 'int') {
             // List of ints is ok
           } else if (type.typeName == 'double') {
@@ -190,25 +224,49 @@
     for (CompilationUnitMember decl in idlParsed.declarations) {
       if (decl is ClassDeclaration) {
         bool isTopLevel = false;
+        String fileIdentifier;
+        String clsName = decl.name.name;
         for (Annotation annotation in decl.metadata) {
-          if (annotation.arguments == null &&
-              annotation.name.name == 'topLevel') {
+          if (annotation.arguments != null &&
+              annotation.name.name == 'TopLevel' &&
+              annotation.constructorName == null) {
             isTopLevel = true;
+            if (annotation.arguments == null) {
+              throw new Exception(
+                  'Class `$clsName`: TopLevel requires parenthesis');
+            }
+            if (annotation.constructorName != null) {
+              throw new Exception(
+                  "Class `$clsName`: TopLevel doesn't have named constructors");
+            }
+            if (annotation.arguments.arguments.length == 1) {
+              Expression arg = annotation.arguments.arguments[0];
+              if (arg is StringLiteral) {
+                fileIdentifier = arg.stringValue;
+              } else {
+                throw new Exception(
+                    'Class `$clsName`: TopLevel argument must be a string'
+                    ' literal');
+              }
+            } else if (annotation.arguments.arguments.length != 0) {
+              throw new Exception(
+                  'Class `$clsName`: TopLevel requires 0 or 1 arguments');
+            }
           }
         }
         String doc = _getNodeDoc(lineInfo, decl);
-        idlModel.ClassDeclaration cls =
-            new idlModel.ClassDeclaration(doc, decl.name.name, isTopLevel);
-        _idl.classes[cls.name] = cls;
+        idlModel.ClassDeclaration cls = new idlModel.ClassDeclaration(
+            doc, clsName, isTopLevel, fileIdentifier);
+        _idl.classes[clsName] = cls;
         String expectedBase = 'base.SummaryClass';
         if (decl.extendsClause == null ||
             decl.extendsClause.superclass.name.name != expectedBase) {
           throw new Exception(
-              'Class `${cls.name}` needs to extend `$expectedBase`');
+              'Class `$clsName` needs to extend `$expectedBase`');
         }
         for (ClassMember classMember in decl.members) {
           if (classMember is MethodDeclaration && classMember.isGetter) {
-            String desc = '${cls.name}.${classMember.name.name}';
+            String desc = '$clsName.${classMember.name.name}';
             TypeName type = classMember.returnType;
             if (type == null) {
               throw new Exception('Class member needs a type: $desc');
@@ -224,6 +282,7 @@
               throw new Exception('Cannot handle type arguments in `$type`');
             }
             int id;
+            bool isDeprecated = false;
             for (Annotation annotation in classMember.metadata) {
               if (annotation.name.name == 'Id') {
                 if (id != null) {
@@ -241,6 +300,11 @@
                   throw new Exception(
                       '@Id parameter must be an integer literal ($desc)');
                 }
+              } else if (annotation.name.name == 'deprecated') {
+                if (annotation.arguments != null) {
+                  throw new Exception('@deprecated does not take args ($desc)');
+                }
+                isDeprecated = true;
               }
             }
             if (id == null) {
@@ -249,8 +313,8 @@
             String doc = _getNodeDoc(lineInfo, classMember);
             idlModel.FieldType fieldType =
                 new idlModel.FieldType(type.name.name, isList);
-            cls.fields.add(new idlModel.FieldDeclaration(
-                doc, classMember.name.name, fieldType, id));
+            cls.allFields.add(new idlModel.FieldDeclaration(
+                doc, classMember.name.name, fieldType, id, isDeprecated));
           } else if (classMember is ConstructorDeclaration &&
               classMember.name.name == 'fromBuffer') {
             // Ignore `fromBuffer` declarations; they simply forward to the
@@ -279,6 +343,128 @@
   }
 
   /**
+   * Generate a string representing the FlatBuffer schema type which should be
+   * used to represent [type].
+   */
+  String fbsType(idlModel.FieldType type) {
+    String typeStr;
+    switch (type.typeName) {
+      case 'bool':
+        typeStr = 'bool';
+        break;
+      case 'double':
+        typeStr = 'double';
+        break;
+      case 'int':
+        typeStr = 'uint';
+        break;
+      case 'String':
+        typeStr = 'string';
+        break;
+      default:
+        typeStr = type.typeName;
+        break;
+    }
+    if (type.isList) {
+      // FlatBuffers don't natively support a packed list of booleans, so we
+      // treat it as a list of unsigned bytes, which is a compatible data
+      // structure.
+      if (typeStr == 'bool') {
+        typeStr = 'ubyte';
+      }
+      return '[$typeStr]';
+    } else {
+      return typeStr;
+    }
+  }
+
+  /**
+   * Entry point to the code generator when generating the "format.fbs" file.
+   */
+  void generateFlatBufferSchema() {
+    outputHeader();
+    for (idlModel.EnumDeclaration enm in _idl.enums.values) {
+      out();
+      outDoc(enm.documentation);
+      out('enum ${enm.name} : byte {');
+      indent(() {
+        for (int i = 0; i < enm.values.length; i++) {
+          idlModel.EnumValueDeclaration value = enm.values[i];
+          if (i != 0) {
+            out();
+          }
+          String suffix = i < enm.values.length - 1 ? ',' : '';
+          outDoc(value.documentation);
+          out('${value.name}$suffix');
+        }
+      });
+      out('}');
+    }
+    for (idlModel.ClassDeclaration cls in _idl.classes.values) {
+      out();
+      outDoc(cls.documentation);
+      out('table ${cls.name} {');
+      indent(() {
+        for (int i = 0; i < cls.allFields.length; i++) {
+          idlModel.FieldDeclaration field = cls.allFields[i];
+          if (i != 0) {
+            out();
+          }
+          outDoc(field.documentation);
+          List<String> attributes = <String>['id: ${field.id}'];
+          if (field.isDeprecated) {
+            attributes.add('deprecated');
+          }
+          String attrText = attributes.join(', ');
+          out('${field.name}:${fbsType(field.type)} ($attrText);');
+        }
+      });
+      out('}');
+    }
+    out();
+    // Standard flatbuffers only support one root type.  We support multiple
+    // root types.  For now work around this by forcing PackageBundle to be the
+    // root type.  TODO(paulberry): come up with a better solution.
+    idlModel.ClassDeclaration rootType = _idl.classes['PackageBundle'];
+    out('root_type ${rootType.name};');
+    if (rootType.fileIdentifier != null) {
+      out();
+      out('file_identifier ${quoted(rootType.fileIdentifier)};');
+    }
+  }
+
+  /**
+   * Entry point to the code generator when generating the "format.dart" file.
+   */
+  void generateFormatCode() {
+    outputHeader();
+    out('library analyzer.src.summary.format;');
+    out();
+    out("import 'flat_buffers.dart' as fb;");
+    out("import 'idl.dart' as idl;");
+    out("import 'dart:convert' as convert;");
+    out();
+    for (idlModel.EnumDeclaration enm in _idl.enums.values) {
+      _generateEnumReader(enm);
+      out();
+    }
+    for (idlModel.ClassDeclaration cls in _idl.classes.values) {
+      _generateBuilder(cls);
+      out();
+      if (cls.isTopLevel) {
+        _generateReadFunction(cls);
+        out();
+      }
+      _generateReader(cls);
+      out();
+      _generateImpl(cls);
+      out();
+      _generateMixin(cls);
+      out();
+    }
+  }
+
+  /**
    * Add the prefix `idl.` to a type name, unless that type name is the name of
    * a built-in type.
    */
@@ -325,13 +511,7 @@
     }
   }
 
-  /**
-   * Entry point to the code generator.  Interpret the AST in [idlParsed],
-   * generate code, and output it to [_outBuffer].
-   */
-  void processCompilationUnit(LineInfo lineInfo, CompilationUnit idlParsed) {
-    extractIdl(lineInfo, idlParsed);
-    checkIdl();
+  void outputHeader() {
     out('// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file');
     out('// for details. All rights reserved. Use of this source code is governed by a');
     out('// BSD-style license that can be found in the LICENSE file.');
@@ -339,30 +519,6 @@
     out('// This file has been automatically generated.  Please do not edit it manually.');
     out('// To regenerate the file, use the script "pkg/analyzer/tool/generate_files".');
     out();
-    out('library analyzer.src.summary.format;');
-    out();
-    out("import 'flat_buffers.dart' as fb;");
-    out("import 'idl.dart' as idl;");
-    out("import 'dart:convert' as convert;");
-    out();
-    for (idlModel.EnumDeclaration enm in _idl.enums.values) {
-      _generateEnumReader(enm);
-      out();
-    }
-    for (idlModel.ClassDeclaration cls in _idl.classes.values) {
-      _generateBuilder(cls);
-      out();
-      if (cls.isTopLevel) {
-        _generateReadFunction(cls);
-        out();
-      }
-      _generateReader(cls);
-      out();
-      _generateImpl(cls);
-      out();
-      _generateMixin(cls);
-      out();
-    }
   }
 
   /**
@@ -390,7 +546,7 @@
         out('$typeStr _$fieldName;');
       }
       // Generate getters and setters.
-      for (idlModel.FieldDeclaration field in cls.fields) {
+      for (idlModel.FieldDeclaration field in cls.allFields) {
         String fieldName = field.name;
         idlModel.FieldType fieldType = field.type;
         String typeStr = encodedType(fieldType);
@@ -398,34 +554,39 @@
         String defSuffix = def == null ? '' : ' ??= $def';
         out();
         out('@override');
-        out('$typeStr get $fieldName => _$fieldName$defSuffix;');
-        out();
-        outDoc(field.documentation);
-        constructorParams.add('$typeStr $fieldName');
-        out('void set $fieldName($typeStr _value) {');
-        indent(() {
-          String stateFieldName = '_' + fieldName;
-          out('assert(!_finished);');
-          // Validate that int(s) are non-negative.
-          if (fieldType.typeName == 'int') {
-            if (!fieldType.isList) {
-              out('assert(_value == null || _value >= 0);');
-            } else {
-              out('assert(_value == null || _value.every((e) => e >= 0));');
+        if (field.isDeprecated) {
+          out('$typeStr get $fieldName => $_throwDeprecated;');
+        } else {
+          out('$typeStr get $fieldName => _$fieldName$defSuffix;');
+          out();
+          outDoc(field.documentation);
+          constructorParams.add('$typeStr $fieldName');
+          out('void set $fieldName($typeStr _value) {');
+          indent(() {
+            String stateFieldName = '_' + fieldName;
+            out('assert(!_finished);');
+            // Validate that int(s) are non-negative.
+            if (fieldType.typeName == 'int') {
+              if (!fieldType.isList) {
+                out('assert(_value == null || _value >= 0);');
+              } else {
+                out('assert(_value == null || _value.every((e) => e >= 0));');
+              }
             }
-          }
-          // Set the value.
-          out('$stateFieldName = _value;');
-        });
-        out('}');
+            // Set the value.
+            out('$stateFieldName = _value;');
+          });
+          out('}');
+        }
       }
       // Generate constructor.
       out();
       out('$builderName({${constructorParams.join(', ')}})');
-      for (int i = 0; i < cls.fields.length; i++) {
-        idlModel.FieldDeclaration field = cls.fields[i];
+      List<idlModel.FieldDeclaration> fields = cls.fields.toList();
+      for (int i = 0; i < fields.length; i++) {
+        idlModel.FieldDeclaration field = fields[i];
         String prefix = i == 0 ? '  : ' : '    ';
-        String suffix = i == cls.fields.length - 1 ? ';' : ',';
+        String suffix = i == fields.length - 1 ? ';' : ',';
         out('${prefix}_${field.name} = ${field.name}$suffix');
       }
       // Generate finish.
@@ -434,7 +595,10 @@
         out('List<int> toBuffer() {');
         indent(() {
           out('fb.Builder fbBuilder = new fb.Builder();');
-          out('return fbBuilder.finish(finish(fbBuilder));');
+          String fileId = cls.fileIdentifier == null
+              ? ''
+              : ', ${quoted(cls.fileIdentifier)}';
+          out('return fbBuilder.finish(finish(fbBuilder)$fileId);');
         });
         out('}');
       }
@@ -469,6 +633,8 @@
               String itemCode = 'b.index';
               String listCode = '$valueName.map((b) => $itemCode).toList()';
               writeCode = '$offsetName = fbBuilder.writeListUint8($listCode);';
+            } else if (fieldType.typeName == 'bool') {
+              writeCode = '$offsetName = fbBuilder.writeListBool($valueName);';
             } else if (fieldType.typeName == 'int') {
               writeCode =
                   '$offsetName = fbBuilder.writeListUint32($valueName);';
@@ -541,6 +707,8 @@
   void _generateEnumReader(idlModel.EnumDeclaration enm) {
     String name = enm.name;
     String readerName = '_${name}Reader';
+    String count = '${idlPrefix(name)}.values.length';
+    String def = '${idlPrefix(name)}.${enm.values[0].name}';
     out('class $readerName extends fb.Reader<${idlPrefix(name)}> {');
     indent(() {
       out('const $readerName() : super();');
@@ -552,7 +720,7 @@
       out('${idlPrefix(name)} read(fb.BufferPointer bp) {');
       indent(() {
         out('int index = const fb.Uint8Reader().read(bp);');
-        out('return ${idlPrefix(name)}.values[index];');
+        out('return index < $count ? ${idlPrefix(name)}.values[index] : $def;');
       });
       out('}');
     });
@@ -577,7 +745,7 @@
         out('$returnType _$fieldName;');
       }
       // Write getters.
-      for (idlModel.FieldDeclaration field in cls.fields) {
+      for (idlModel.FieldDeclaration field in cls.allFields) {
         int index = field.id;
         String fieldName = field.name;
         idlModel.FieldType type = field.type;
@@ -586,7 +754,9 @@
         String readCode;
         String def = defaultValue(type, false);
         if (type.isList) {
-          if (typeName == 'int') {
+          if (typeName == 'bool') {
+            readCode = 'const fb.BoolListReader()';
+          } else if (typeName == 'int') {
             readCode = 'const fb.Uint32ListReader()';
           } else if (typeName == 'double') {
             readCode = 'const fb.Float64ListReader()';
@@ -617,13 +787,17 @@
         out();
         out('@override');
         String returnType = dartType(type);
-        out('$returnType get $fieldName {');
-        indent(() {
-          String readExpr = '$readCode.vTableGet(_bp, $index, $def)';
-          out('_$fieldName ??= $readExpr;');
-          out('return _$fieldName;');
-        });
-        out('}');
+        if (field.isDeprecated) {
+          out('$returnType get $fieldName => $_throwDeprecated;');
+        } else {
+          out('$returnType get $fieldName {');
+          indent(() {
+            String readExpr = '$readCode.vTableGet(_bp, $index, $def)';
+            out('_$fieldName ??= $readExpr;');
+            out('return _$fieldName;');
+          });
+          out('}');
+        }
       }
     });
     out('}');
diff --git a/pkg/analyzer/tool/summary/idl_model.dart b/pkg/analyzer/tool/summary/idl_model.dart
index fca1054..9ec248f 100644
--- a/pkg/analyzer/tool/summary/idl_model.dart
+++ b/pkg/analyzer/tool/summary/idl_model.dart
@@ -14,17 +14,30 @@
  */
 class ClassDeclaration extends Declaration {
   /**
-   * Fields defined in the class.
+   * All fields defined in the class, including deprecated ones.
    */
-  final List<FieldDeclaration> fields = <FieldDeclaration>[];
+  final List<FieldDeclaration> allFields = <FieldDeclaration>[];
 
   /**
    * Indicates whether the class has the `topLevel` annotation.
    */
   final bool isTopLevel;
 
-  ClassDeclaration(String documentation, String name, this.isTopLevel)
+  /**
+   * If [isTopLevel] is `true` and a file identifier was specified for this
+   * class, the file identifier string.  Otheswise `null`.
+   */
+  final String fileIdentifier;
+
+  ClassDeclaration(
+      String documentation, String name, this.isTopLevel, this.fileIdentifier)
       : super(documentation, name);
+
+  /**
+   * Get the non-deprecated fields defined in the class.
+   */
+  Iterable<FieldDeclaration> get fields =>
+      allFields.where((FieldDeclaration field) => !field.isDeprecated);
 }
 
 /**
@@ -79,7 +92,13 @@
    */
   final int id;
 
-  FieldDeclaration(String documentation, String name, this.type, this.id)
+  /**
+   * Indicates whether the field is deprecated.
+   */
+  final bool isDeprecated;
+
+  FieldDeclaration(
+      String documentation, String name, this.type, this.id, this.isDeprecated)
       : super(documentation, name);
 }
 
diff --git a/pkg/analyzer_cli/lib/src/package_analyzer.dart b/pkg/analyzer_cli/lib/src/package_analyzer.dart
index 0bad260..746c77a 100644
--- a/pkg/analyzer_cli/lib/src/package_analyzer.dart
+++ b/pkg/analyzer_cli/lib/src/package_analyzer.dart
@@ -4,7 +4,6 @@
 
 library analyzer_cli.src.package_analyzer;
 
-import 'dart:convert';
 import 'dart:core' hide Resource;
 import 'dart:io' as io;
 
@@ -12,231 +11,22 @@
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/file_system/physical_file_system.dart';
 import 'package:analyzer/source/package_map_resolver.dart';
-import 'package:analyzer/src/context/cache.dart';
-import 'package:analyzer/src/context/context.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/error.dart';
-import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/java_io.dart';
 import 'package:analyzer/src/generated/sdk_io.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/source_io.dart';
 import 'package:analyzer/src/summary/format.dart';
-import 'package:analyzer/src/summary/idl.dart';
-import 'package:analyzer/src/summary/resynthesize.dart';
+import 'package:analyzer/src/summary/package_bundle_reader.dart';
 import 'package:analyzer/src/summary/summarize_elements.dart';
-import 'package:analyzer/src/summary/summary_sdk.dart';
-import 'package:analyzer/src/task/dart.dart';
-import 'package:analyzer/task/dart.dart';
-import 'package:analyzer/task/model.dart';
 import 'package:analyzer_cli/src/analyzer_impl.dart';
 import 'package:analyzer_cli/src/driver.dart';
 import 'package:analyzer_cli/src/error_formatter.dart';
 import 'package:analyzer_cli/src/options.dart';
-import 'package:crypto/crypto.dart';
 import 'package:path/path.dart' as pathos;
 
 /**
- * If [uri] has the `package` scheme in form of `package:pkg/file.dart`,
- * return the `pkg` name.  Otherwise return `null`.
- */
-String getPackageName(Uri uri) {
-  if (uri.scheme != 'package') {
-    return null;
-  }
-  String path = uri.path;
-  int index = path.indexOf('/');
-  if (index == -1) {
-    return null;
-  }
-  return path.substring(0, index);
-}
-
-/**
- * A concrete resynthesizer that serves summaries from given file paths.
- */
-class FileBasedSummaryResynthesizer extends SummaryResynthesizer {
-  final Map<String, UnlinkedUnit> unlinkedMap = <String, UnlinkedUnit>{};
-  final Map<String, LinkedLibrary> linkedMap = <String, LinkedLibrary>{};
-
-  FileBasedSummaryResynthesizer(
-      SummaryResynthesizer parent,
-      AnalysisContext context,
-      TypeProvider typeProvider,
-      SourceFactory sourceFactory,
-      bool strongMode,
-      List<String> summaryPaths)
-      : super(parent, context, typeProvider, sourceFactory, strongMode) {
-    summaryPaths.forEach(_fillMaps);
-  }
-
-  @override
-  LinkedLibrary getLinkedSummary(String uri) {
-    return linkedMap[uri];
-  }
-
-  @override
-  UnlinkedUnit getUnlinkedSummary(String uri) {
-    return unlinkedMap[uri];
-  }
-
-  @override
-  bool hasLibrarySummary(String uri) {
-    return linkedMap.containsKey(uri);
-  }
-
-  void _fillMaps(String path) {
-    io.File file = new io.File(path);
-    List<int> buffer = file.readAsBytesSync();
-    PackageBundle bundle = new PackageBundle.fromBuffer(buffer);
-    for (int i = 0; i < bundle.unlinkedUnitUris.length; i++) {
-      unlinkedMap[bundle.unlinkedUnitUris[i]] = bundle.unlinkedUnits[i];
-    }
-    for (int i = 0; i < bundle.linkedLibraryUris.length; i++) {
-      linkedMap[bundle.linkedLibraryUris[i]] = bundle.linkedLibraries[i];
-    }
-  }
-}
-
-/**
- * The [ResultProvider] that provides results from input package summaries.
- */
-class InputPackagesResultProvider extends ResultProvider {
-  final InternalAnalysisContext context;
-  final Map<String, String> packageSummaryInputs;
-
-  FileBasedSummaryResynthesizer resynthesizer;
-  SummaryResultProvider sdkProvider;
-
-  InputPackagesResultProvider(this.context, this.packageSummaryInputs) {
-    InternalAnalysisContext sdkContext = context.sourceFactory.dartSdk.context;
-    sdkProvider = sdkContext.resultProvider;
-    // Set the type provider to prevent the context from computing it.
-    context.typeProvider = sdkContext.typeProvider;
-    // Create a chained resynthesizer.
-    resynthesizer = new FileBasedSummaryResynthesizer(
-        sdkProvider.resynthesizer,
-        context,
-        context.typeProvider,
-        context.sourceFactory,
-        context.analysisOptions.strongMode,
-        packageSummaryInputs.values.toList());
-  }
-
-  bool compute(CacheEntry entry, ResultDescriptor result) {
-    if (sdkProvider.compute(entry, result)) {
-      return true;
-    }
-    AnalysisTarget target = entry.target;
-    // Only library results are supported for now.
-    if (target is Source) {
-      Uri uri = target.uri;
-      // We know how to server results to input packages.
-      String sourcePackageName = getPackageName(uri);
-      if (!packageSummaryInputs.containsKey(sourcePackageName)) {
-        return false;
-      }
-      // Provide known results.
-      String uriString = uri.toString();
-      if (result == LIBRARY_ELEMENT1 ||
-          result == LIBRARY_ELEMENT2 ||
-          result == LIBRARY_ELEMENT3 ||
-          result == LIBRARY_ELEMENT4 ||
-          result == LIBRARY_ELEMENT5 ||
-          result == LIBRARY_ELEMENT6 ||
-          result == LIBRARY_ELEMENT7 ||
-          result == LIBRARY_ELEMENT8 ||
-          result == LIBRARY_ELEMENT ||
-          false) {
-        LibraryElement libraryElement =
-            resynthesizer.getLibraryElement(uriString);
-        entry.setValue(result, libraryElement, TargetedResult.EMPTY_LIST);
-        return true;
-      } else if (result == READY_LIBRARY_ELEMENT2 ||
-          result == READY_LIBRARY_ELEMENT5 ||
-          result == READY_LIBRARY_ELEMENT6) {
-        entry.setValue(result, true, TargetedResult.EMPTY_LIST);
-        return true;
-      } else if (result == SOURCE_KIND) {
-        if (resynthesizer.linkedMap.containsKey(uriString)) {
-          entry.setValue(result, SourceKind.LIBRARY, TargetedResult.EMPTY_LIST);
-          return true;
-        }
-        if (resynthesizer.unlinkedMap.containsKey(uriString)) {
-          entry.setValue(result, SourceKind.PART, TargetedResult.EMPTY_LIST);
-          return true;
-        }
-        return false;
-      }
-    }
-    return false;
-  }
-}
-
-/**
- * The [UriResolver] that knows about sources that are parts of packages which
- * are served from their summaries.
- */
-class InSummaryPackageUriResolver extends UriResolver {
-  final Map<String, String> packageSummaryInputs;
-
-  InSummaryPackageUriResolver(this.packageSummaryInputs);
-
-  @override
-  Source resolveAbsolute(Uri uri, [Uri actualUri]) {
-    actualUri ??= uri;
-    String packageName = getPackageName(actualUri);
-    if (packageSummaryInputs.containsKey(packageName)) {
-      return new InSummarySource(actualUri);
-    }
-    return null;
-  }
-}
-
-/**
- * A placeholder of a source that is part of a package whose analysis results
- * are served from its summary.  This source uses its URI as [fullName] and has
- * empty contents.
- */
-class InSummarySource extends Source {
-  final Uri uri;
-
-  InSummarySource(this.uri);
-
-  @override
-  TimestampedData<String> get contents => new TimestampedData<String>(0, '');
-
-  @override
-  String get encoding => uri.toString();
-
-  @override
-  String get fullName => encoding;
-
-  @override
-  bool get isInSystemLibrary => false;
-
-  @override
-  int get modificationStamp => 0;
-
-  @override
-  String get shortName => pathos.basename(fullName);
-
-  @override
-  UriKind get uriKind => UriKind.PACKAGE_URI;
-
-  @override
-  bool exists() => true;
-
-  @override
-  Uri resolveRelativeUri(Uri relativeUri) {
-    Uri baseUri = uri;
-    return baseUri.resolveUri(relativeUri);
-  }
-
-  @override
-  String toString() => uri.toString();
-}
-
-/**
  * The hermetic whole package analyzer.
  */
 class PackageAnalyzer {
@@ -249,12 +39,6 @@
   InternalAnalysisContext context;
   final List<Source> explicitSources = <Source>[];
 
-  final List<String> linkedLibraryUris = <String>[];
-  final List<LinkedLibraryBuilder> linkedLibraries = <LinkedLibraryBuilder>[];
-  final List<String> unlinkedUnitUris = <String>[];
-  final List<UnlinkedUnitBuilder> unlinkedUnits = <UnlinkedUnitBuilder>[];
-  final List<String> unlinkedUnitHashes = <String>[];
-
   PackageAnalyzer(this.options);
 
   /**
@@ -306,21 +90,17 @@
 
     // Write summary for Dart libraries.
     if (options.packageSummaryOutput != null) {
+      PackageBundleAssembler assembler = new PackageBundleAssembler();
       for (Source source in context.librarySources) {
         if (pathos.isWithin(packageLibPath, source.fullName)) {
           LibraryElement libraryElement = context.getLibraryElement(source);
           if (libraryElement != null) {
-            _serializeSingleLibrary(libraryElement);
+            assembler.serializeLibraryElement(libraryElement);
           }
         }
       }
       // Write the whole package bundle.
-      PackageBundleBuilder sdkBundle = new PackageBundleBuilder(
-          linkedLibraryUris: linkedLibraryUris,
-          linkedLibraries: linkedLibraries,
-          unlinkedUnitUris: unlinkedUnitUris,
-          unlinkedUnits: unlinkedUnits,
-          unlinkedUnitHashes: unlinkedUnitHashes);
+      PackageBundleBuilder sdkBundle = assembler.assemble();
       io.File file = new io.File(options.packageSummaryOutput);
       file.writeAsBytesSync(sdkBundle.toBuffer(), mode: io.FileMode.WRITE_ONLY);
     }
@@ -346,12 +126,11 @@
   }
 
   void _createContext() {
-    DirectoryBasedDartSdk sdk = DirectoryBasedDartSdk.defaultSdk;
-    sdk.useSummary = true;
+    DirectoryBasedDartSdk sdk =
+        new DirectoryBasedDartSdk(new JavaFile(options.dartSdkPath));
 
     // Create the context.
     context = AnalysisEngine.instance.createAnalysisContext();
-    context.typeProvider = sdk.context.typeProvider;
     context.sourceFactory = new SourceFactory(<UriResolver>[
       new DartUriResolver(sdk),
       new InSummaryPackageUriResolver(options.packageSummaryInputs),
@@ -367,7 +146,9 @@
     Driver.setAnalysisContextOptions(
         context, options, (AnalysisOptionsImpl contextOptions) {});
 
-    // Set the result provider.
+    // Configure using summaries.
+    sdk.useSummary = true;
+    context.typeProvider = sdk.context.typeProvider;
     context.resultProvider =
         new InputPackagesResultProvider(context, options.packageSummaryInputs);
   }
@@ -385,15 +166,6 @@
   }
 
   /**
-   * Compute a hash of the given file contents.
-   */
-  String _hash(String contents) {
-    MD5 md5 = new MD5();
-    md5.add(UTF8.encode(contents));
-    return CryptoUtils.bytesToHex(md5.close());
-  }
-
-  /**
    * Print errors for all explicit sources.
    */
   void _printErrors() {
@@ -408,20 +180,4 @@
       formatter.formatErrors([errorInfo]);
     }
   }
-
-  /**
-   * Serialize the library with the given [element].
-   */
-  void _serializeSingleLibrary(LibraryElement element) {
-    String uri = element.source.uri.toString();
-    LibrarySerializationResult libraryResult =
-        serializeLibrary(element, context.typeProvider, options.strongMode);
-    linkedLibraryUris.add(uri);
-    linkedLibraries.add(libraryResult.linked);
-    unlinkedUnitUris.addAll(libraryResult.unitUris);
-    unlinkedUnits.addAll(libraryResult.unlinkedUnits);
-    for (Source source in libraryResult.unitSources) {
-      unlinkedUnitHashes.add(_hash(source.contents.data));
-    }
-  }
 }
diff --git a/pkg/compiler/lib/src/cps_ir/backward_null_check_remover.dart b/pkg/compiler/lib/src/cps_ir/backward_null_check_remover.dart
index 6a2c16f..de027ec 100644
--- a/pkg/compiler/lib/src/cps_ir/backward_null_check_remover.dart
+++ b/pkg/compiler/lib/src/cps_ir/backward_null_check_remover.dart
@@ -50,9 +50,8 @@
     BlockVisitor.traverseInPostOrder(node, this);
   }
 
-  /// Returns a reference to an operand of [prim], where [prim] throws if null
-  /// is passed into that operand.
-  Reference<Primitive> getNullCheckedOperand(Primitive prim) {
+  /// Returns an operand of [prim] that throws if null is passed into it.
+  Primitive getNullCheckedOperand(Primitive prim) {
     if (prim is ReceiverCheck) return prim.value;
     if (prim is GetLength) return prim.object;
     if (prim is GetField) return prim.object;
@@ -60,10 +59,10 @@
     if (prim is SetField) return prim.object;
     if (prim is SetIndex) return prim.object;
     if (prim is InvokeMethod && !selectorsOnNull.contains(prim.selector)) {
-      return prim.dartReceiverReference;
+      return prim.dartReceiver;
     }
     if (prim is ForeignCode) {
-      return prim.isNullGuardOnNullFirstArgument() ? prim.arguments[0] : null;
+      return prim.isNullGuardOnNullFirstArgument() ? prim.argument(0) : null;
     }
     return null;
   }
@@ -72,7 +71,7 @@
   /// [newNullCheck].  Eliminate [prim] if it is not needed any more.
   void tryEliminateRedundantNullCheck(Primitive prim, Primitive newNullCheck) {
     if (prim is ReceiverCheck && prim.isNullCheck) {
-      Primitive value = prim.value.definition;
+      Primitive value = prim.value;
       LetPrim let = prim.parent;
       prim..replaceUsesWith(value)..destroy();
       let.remove();
@@ -99,7 +98,7 @@
 
   void visitLetPrim(LetPrim node) {
     Primitive prim = node.primitive;
-    Primitive receiver = getNullCheckedOperand(prim)?.definition;
+    Primitive receiver = getNullCheckedOperand(prim);
     if (receiver != null) {
       if (nullCheckedValue != null && receiver.sameValue(nullCheckedValue)) {
         tryEliminateRedundantNullCheck(prim, nullCheckedValue);
@@ -123,7 +122,7 @@
 
   visitInvokeContinuation(InvokeContinuation node) {
     if (!node.isRecursive) {
-      nullCheckedValue = nullCheckedValueAt[node.continuation.definition];
+      nullCheckedValue = nullCheckedValueAt[node.continuation];
     }
   }
 }
diff --git a/pkg/compiler/lib/src/cps_ir/bounds_checker.dart b/pkg/compiler/lib/src/cps_ir/bounds_checker.dart
index 798875f..b357c99 100644
--- a/pkg/compiler/lib/src/cps_ir/bounds_checker.dart
+++ b/pkg/compiler/lib/src/cps_ir/bounds_checker.dart
@@ -14,6 +14,7 @@
 import '../world.dart';
 import '../elements/elements.dart';
 import 'loop_effects.dart';
+import 'effects.dart';
 
 /// Eliminates bounds checks when they can be proven safe.
 ///
@@ -268,9 +269,9 @@
 
   @override
   void visitBranch(Branch node) {
-    Primitive condition = node.condition.definition;
-    Continuation trueCont = node.trueContinuation.definition;
-    Continuation falseCont = node.falseContinuation.definition;
+    Primitive condition = node.condition;
+    Continuation trueCont = node.trueContinuation;
+    Continuation falseCont = node.falseContinuation;
     effectNumberAt[trueCont] = currentEffectNumber;
     effectNumberAt[falseCont] = currentEffectNumber;
     pushAction(() {
@@ -300,11 +301,11 @@
       });
     }
     if (condition is ApplyBuiltinOperator &&
-        condition.arguments.length == 2 &&
-        isInt(condition.arguments[0].definition) &&
-        isInt(condition.arguments[1].definition)) {
-      SignedVariable v1 = getValue(condition.arguments[0].definition);
-      SignedVariable v2 = getValue(condition.arguments[1].definition);
+        condition.argumentRefs.length == 2 &&
+        isInt(condition.argument(0)) &&
+        isInt(condition.argument(1))) {
+      SignedVariable v1 = getValue(condition.argument(0));
+      SignedVariable v2 = getValue(condition.argument(1));
       switch (condition.operator) {
         case BuiltinOperator.NumLe:
           pushTrue(() => makeLessThanOrEqual(v1, v2));
@@ -351,16 +352,16 @@
   @override
   void visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
     if (!isInt(node)) return;
-    if (node.arguments.length == 1) {
+    if (node.argumentRefs.length == 1) {
       applyUnaryOperator(node);
-    } else if (node.arguments.length == 2) {
+    } else if (node.argumentRefs.length == 2) {
       applyBinaryOperator(node);
     }
   }
 
   void applyBinaryOperator(ApplyBuiltinOperator node) {
-    Primitive left = node.arguments[0].definition;
-    Primitive right = node.arguments[1].definition;
+    Primitive left = node.argument(0);
+    Primitive right = node.argument(1);
     if (!isInt(left) || !isInt(right)) {
       return;
     }
@@ -461,7 +462,7 @@
   }
 
   void applyUnaryOperator(ApplyBuiltinOperator node) {
-    Primitive argument = node.arguments[0].definition;
+    Primitive argument = node.argument(0);
     if (!isInt(argument)) return;
     if (node.operator == BuiltinOperator.NumNegate) {
       valueOf[node] = getValue(argument).negated;
@@ -486,17 +487,17 @@
 
   @override
   void visitGetLength(GetLength node) {
-    valueOf[node] = getLength(node.object.definition, currentEffectNumber);
+    valueOf[node] = getLength(node.object, currentEffectNumber);
   }
 
   @override
   void visitBoundsCheck(BoundsCheck node) {
     if (node.checks == BoundsCheck.NONE) return;
-    assert(node.index != null); // Because there is at least one check.
-    SignedVariable length = node.length == null
+    assert(node.indexRef != null); // Because there is at least one check.
+    SignedVariable length = node.lengthRef == null
         ? null
-        : getValue(node.length.definition);
-    SignedVariable index = getValue(node.index.definition);
+        : getValue(node.length);
+    SignedVariable index = getValue(node.index);
     if (node.hasUpperBoundCheck) {
       if (isDefinitelyLessThan(index, length)) {
         node.checks &= ~BoundsCheck.UPPER_BOUND;
@@ -518,24 +519,24 @@
         makeGreaterThanOrEqualToConstant(length, 1);
       }
     }
-    if (!node.lengthUsedInCheck && node.length != null) {
-      node..length.unlink()..length = null;
+    if (!node.lengthUsedInCheck && node.lengthRef != null) {
+      node..lengthRef.unlink()..lengthRef = null;
     }
     if (node.checks == BoundsCheck.NONE) {
       // We can't remove the bounds check node because it may still be used to
       // restrict code motion.  But the index is no longer needed.
-      node..index.unlink()..index = null;
+      node..indexRef.unlink()..indexRef = null;
     }
   }
 
   void analyzeLoopEntry(InvokeContinuation node) {
     foundLoop = true;
-    Continuation cont = node.continuation.definition;
+    Continuation cont = node.continuation;
     if (isStrongLoopPass) {
-      for (int i = 0; i < node.arguments.length; ++i) {
+      for (int i = 0; i < node.argumentRefs.length; ++i) {
         Parameter param = cont.parameters[i];
         if (!isInt(param)) continue;
-        Primitive initialValue = node.arguments[i].definition;
+        Primitive initialValue = node.argument(i);
         SignedVariable initialVariable = getValue(initialValue);
         Monotonicity mono = monotonicity[param];
         if (mono == null) {
@@ -548,14 +549,14 @@
         }
       }
     }
-    if (loopEffects.loopChangesLength(cont)) {
+    if (loopEffects.changesIndexableLength(cont)) {
       currentEffectNumber = effectNumberAt[cont] = makeNewEffect();
     }
     push(cont);
   }
 
   void analyzeLoopContinue(InvokeContinuation node) {
-    Continuation cont = node.continuation.definition;
+    Continuation cont = node.continuation;
 
     // During the strong loop phase, there is no need to compute monotonicity,
     // and we already put bounds on the loop variables when we went into the
@@ -565,10 +566,10 @@
     // For each loop parameter, try to prove that the new value is definitely
     // less/greater than its old value. When we fail to prove this, update the
     // monotonicity flag accordingly.
-    for (int i = 0; i < node.arguments.length; ++i) {
+    for (int i = 0; i < node.argumentRefs.length; ++i) {
       Parameter param = cont.parameters[i];
       if (!isInt(param)) continue;
-      SignedVariable arg = getValue(node.arguments[i].definition);
+      SignedVariable arg = getValue(node.argument(i));
       SignedVariable paramVar = getValue(param);
       if (!isDefinitelyLessThanOrEqualTo(arg, paramVar)) {
         // We couldn't prove that the value does not increase, so assume
@@ -594,7 +595,7 @@
 
   @override
   void visitInvokeContinuation(InvokeContinuation node) {
-    Continuation cont = node.continuation.definition;
+    Continuation cont = node.continuation;
     if (node.isRecursive) {
       analyzeLoopContinue(node);
     } else if (cont.isRecursive) {
@@ -613,6 +614,18 @@
   // ---------------- PRIMITIVES --------------------
 
   @override
+  Expression traverseLetPrim(LetPrim node) {
+    visit(node.primitive);
+    // visitApplyBuiltinMethod updates the effect number.
+    if (node.primitive is! ApplyBuiltinMethod) {
+      if (node.primitive.effects & Effects.changesIndexableLength != 0) {
+        currentEffectNumber = makeNewEffect();
+      }
+    }
+    return node.body;
+  }
+
+  @override
   void visitInvokeMethod(InvokeMethod node) {
     if (node.selector.isGetter && node.selector.name == 'length') {
       // If the receiver type is not known to be indexable, the length call
@@ -624,70 +637,11 @@
         valueOf[node] = getLength(node.dartReceiver, currentEffectNumber);
       }
     }
-    // TODO(asgerf): What we really need is a "changes length" side effect flag.
-    if (world
-        .getSideEffectsOfSelector(node.selector, node.mask)
-        .changesIndex()) {
-      currentEffectNumber = makeNewEffect();
-    }
-  }
-
-  @override
-  void visitInvokeStatic(InvokeStatic node) {
-    if (world.getSideEffectsOfElement(node.target).changesIndex()) {
-      currentEffectNumber = makeNewEffect();
-    }
-  }
-
-  @override
-  void visitInvokeMethodDirectly(InvokeMethodDirectly node) {
-    FunctionElement target = node.target;
-    if (target is ConstructorBodyElement) {
-      ConstructorBodyElement body = target;
-      target = body.constructor;
-    }
-    if (world.getSideEffectsOfElement(target).changesIndex()) {
-      currentEffectNumber = makeNewEffect();
-    }
-  }
-
-  @override
-  void visitInvokeConstructor(InvokeConstructor node) {
-    if (world.getSideEffectsOfElement(node.target).changesIndex()) {
-      currentEffectNumber = makeNewEffect();
-    }
-  }
-
-  @override
-  void visitTypeCast(TypeCast node) {
-  }
-
-  @override
-  void visitGetLazyStatic(GetLazyStatic node) {
-    // TODO(asgerf): How do we get the side effects of a lazy field initializer?
-    currentEffectNumber = makeNewEffect();
-  }
-
-  @override
-  void visitForeignCode(ForeignCode node) {
-    if (node.nativeBehavior.sideEffects.changesIndex()) {
-      currentEffectNumber = makeNewEffect();
-    }
-  }
-
-  @override
-  void visitAwait(Await node) {
-    currentEffectNumber = makeNewEffect();
-  }
-
-  @override
-  void visitYield(Yield node) {
-    currentEffectNumber = makeNewEffect();
   }
 
   @override
   void visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
-    Primitive receiver = node.receiver.definition;
+    Primitive receiver = node.receiver;
     int effectBefore = currentEffectNumber;
     currentEffectNumber = makeNewEffect();
     int effectAfter = currentEffectNumber;
@@ -696,7 +650,7 @@
     switch (node.method) {
       case BuiltinMethod.Push:
         // after = before + count
-        int count = node.arguments.length;
+        int count = node.argumentRefs.length;
         makeExactSum(lengthAfter, lengthBefore, count);
         break;
 
@@ -704,12 +658,16 @@
         // after = before - 1
         makeExactSum(lengthAfter, lengthBefore, -1);
         break;
+
+      case BuiltinMethod.SetLength:
+        makeEqual(lengthAfter, getValue(node.argument(0)));
+        break;
     }
   }
 
   @override
   void visitLiteralList(LiteralList node) {
-    makeConstant(getLength(node, currentEffectNumber), node.values.length);
+    makeConstant(getLength(node, currentEffectNumber), node.valueRefs.length);
   }
 
   // ---------------- INTERIOR EXPRESSIONS --------------------
diff --git a/pkg/compiler/lib/src/cps_ir/builtin_operator.dart b/pkg/compiler/lib/src/cps_ir/builtin_operator.dart
index 7992821..5751644 100644
--- a/pkg/compiler/lib/src/cps_ir/builtin_operator.dart
+++ b/pkg/compiler/lib/src/cps_ir/builtin_operator.dart
@@ -5,6 +5,8 @@
 // This is shared by the CPS and Tree IRs.
 // Both cps_ir_nodes and tree_ir_nodes import and re-export this file.
 
+import 'effects.dart';
+
 /// An operator supported natively in the CPS and Tree IRs using the
 /// `ApplyBuiltinOperator` instructions.
 ///
@@ -187,7 +189,7 @@
 /// but may not depend on or mutate any other state. An exception is thrown
 /// if the object is null, but otherwise they cannot throw or diverge.
 enum BuiltinMethod {
-  /// Add an item to a native list.
+  /// Add an item to an array.
   ///
   /// Takes any number of arguments, each argument will be added to the
   /// list on the order given (as per the JS `push` method).
@@ -195,12 +197,17 @@
   /// Compiles to `object.push(x1, ..., xN)`.
   Push,
 
-  /// Remove and return the last item from a native list.
+  /// Remove and return the last item from an array.
   ///
   /// Takes no arguments.
   ///
   /// Compiles to `object.pop()`.
   Pop,
+
+  /// Sets the length of the array.
+  ///
+  /// Compiles to `object.length = x1`.
+  SetLength,
 }
 
 /// True for the built-in operators that may be used in a compound assignment.
@@ -217,3 +224,17 @@
       return false;
   }
 }
+
+int getEffectsOfBuiltinMethod(BuiltinMethod method) {
+  switch (method) {
+    case BuiltinMethod.Push:
+      return Effects.changesIndexableContent |
+             Effects.changesIndexableLength;
+    case BuiltinMethod.Pop:
+      return Effects.dependsOnIndexableContent |
+             Effects.dependsOnIndexableLength |
+             Effects.changesIndexableLength;
+    case BuiltinMethod.SetLength:
+      return Effects.changesIndexableLength;
+  }
+}
diff --git a/pkg/compiler/lib/src/cps_ir/cps_fragment.dart b/pkg/compiler/lib/src/cps_ir/cps_fragment.dart
index 7e62fa5..f30375a 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_fragment.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_fragment.dart
@@ -124,7 +124,6 @@
                           {bool receiverIsNotNull: false}) {
     ApplyBuiltinMethod apply =
         new ApplyBuiltinMethod(method, receiver, arguments, sourceInformation);
-    apply.receiverIsNotNull = receiverIsNotNull;
     return letPrim(apply);
   }
 
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
index 8ec5743..95fa11a 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
@@ -343,8 +343,8 @@
         arguments.add(new ir.Reference(invocationEnvironment[varIndex]));
       }
       ir.InvokeContinuation invocation = _invocations[jumpIndex];
-      invocation.continuation = new ir.Reference(_continuation);
-      invocation.arguments = arguments;
+      invocation.continuationRef = new ir.Reference(_continuation);
+      invocation.argumentRefs = arguments;
     }
   }
 }
@@ -2588,7 +2588,8 @@
   }
 
   ir.Primitive buildFieldGet(ir.Primitive receiver, FieldElement target) {
-    return addPrimitive(new ir.GetField(receiver, target));
+    return addPrimitive(new ir.GetField(receiver, target,
+        isFinal: program.fieldNeverChanges(target)));
   }
 
   void buildFieldSet(ir.Primitive receiver,
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
index 629bfac..cfea55a 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
@@ -878,9 +878,13 @@
       typeMaskSystem.associateConstantValueWithElement(constant, field);
       return irBuilder.buildConstant(constant, sourceInformation: src);
     } else if (backend.constants.lazyStatics.contains(field)) {
-      return irBuilder.addPrimitive(new ir.GetLazyStatic(field, src));
+      return irBuilder.addPrimitive(new ir.GetLazyStatic(field,
+          sourceInformation: src,
+          isFinal: compiler.world.fieldNeverChanges(field)));
     } else {
-      return irBuilder.addPrimitive(new ir.GetStatic(field, src));
+      return irBuilder.addPrimitive(new ir.GetStatic(field,
+          sourceInformation: src,
+          isFinal: compiler.world.fieldNeverChanges(field)));
     }
   }
 
@@ -1936,7 +1940,7 @@
       ast.Send node,
       MethodElement function,
       _) {
-    return irBuilder.addPrimitive(new ir.GetStatic(function));
+    return irBuilder.addPrimitive(new ir.GetStatic(function, isFinal: true));
   }
 
   @override
@@ -2902,7 +2906,8 @@
         case CompoundGetter.GETTER:
           return buildStaticGetterGet(getter, node);
         case CompoundGetter.METHOD:
-          return irBuilder.addPrimitive(new ir.GetStatic(getter));
+          return irBuilder.addPrimitive(new ir.GetStatic(getter,
+              isFinal: true));
         case CompoundGetter.UNRESOLVED:
           return irBuilder.buildStaticNoSuchMethod(
               new Selector.getter(new Name(getter.name, getter.library)),
@@ -2942,7 +2947,8 @@
         case CompoundGetter.GETTER:
           return buildStaticGetterGet(getter, node);
         case CompoundGetter.METHOD:
-          return irBuilder.addPrimitive(new ir.GetStatic(getter));
+          return irBuilder.addPrimitive(new ir.GetStatic(getter,
+              isFinal: true));
         case CompoundGetter.UNRESOLVED:
           return irBuilder.buildStaticNoSuchMethod(
               new Selector.getter(new Name(getter.name, getter.library)),
@@ -4014,6 +4020,10 @@
     return _compiler.world.locateSingleField(selector, type);
   }
 
+  bool fieldNeverChanges(FieldElement field) {
+    return _compiler.world.fieldNeverChanges(field);
+  }
+
   Element get closureConverter {
     return _backend.helpers.closureConverter;
   }
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_integrity.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_integrity.dart
index a295902..8fb65a2 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_integrity.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_integrity.dart
@@ -110,7 +110,7 @@
   @override
   Expression traverseLetMutable(LetMutable node) {
     handleDeclaration(node.variable);
-    processReference(node.value);
+    processReference(node.valueRef);
 
     // Put the primitive in scope when visiting the body.
     enterScope([node.variable]);
@@ -166,7 +166,7 @@
 
   @override
   processInvokeContinuation(InvokeContinuation node) {
-    Continuation target = node.continuation.definition;
+    Continuation target = node.continuation;
     if (node.isRecursive && inScope[target] == ScopeType.InScope) {
       error('Non-recursive InvokeContinuation marked as recursive', node);
     }
@@ -176,7 +176,7 @@
     if (node.isRecursive && !target.isRecursive) {
       error('Recursive Continuation was not marked as recursive', node);
     }
-    if (node.arguments.length != target.parameters.length) {
+    if (node.argumentRefs.length != target.parameters.length) {
       error('Arity mismatch in InvokeContinuation', node);
     }
   }
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
index 1562262..61a5ddd 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
@@ -12,10 +12,13 @@
 import '../io/source_information.dart' show SourceInformation;
 import '../types/types.dart' show TypeMask;
 import '../universe/selector.dart' show Selector;
+import '../universe/side_effects.dart';
 
 import 'builtin_operator.dart';
 export 'builtin_operator.dart';
 
+import 'effects.dart';
+
 // These imports are only used for the JavaScript specific nodes.  If we want to
 // support more than one native backend, we should probably create better
 // abstractions for native code and its type and effect system.
@@ -64,7 +67,8 @@
   /// same node.
   String debugString([Map annotations]) {
     return new SExpressionStringifier()
-        .withAnnotations(annotations).visit(this);
+        .withAnnotations(annotations)
+        .visit(this);
   }
 
   /// Prints the result of [debugString].
@@ -115,70 +119,17 @@
   accept(BlockVisitor visitor);
 }
 
-/// An expression that creates new bindings and continues evaluation in
-/// a subexpression.
-///
-/// The interior expressions are [LetPrim], [LetCont], [LetHandler], and
-/// [LetMutable].
-abstract class InteriorExpression extends Expression implements InteriorNode {
-  Expression get next => body;
-
-  /// Removes this expression from its current position in the IR.
-  ///
-  /// The node can be re-inserted elsewhere or remain orphaned.
-  ///
-  /// If orphaned, the caller is responsible for unlinking all references in
-  /// the orphaned node. Use [Reference.unlink] or [Primitive.destroy] for this.
-  void remove() {
-    assert(parent != null);
-    assert(parent.body == this);
-    assert(body.parent == this);
-    parent.body = body;
-    body.parent = parent;
-    parent = null;
-    body = null;
-  }
-
-  /// Inserts this above [node].
-  ///
-  /// This node must be orphaned first.
-  void insertAbove(Expression node) {
-    insertBelow(node.parent);
-  }
-
-  /// Inserts this below [node].
-  ///
-  /// This node must be orphaned first.
-  void insertBelow(InteriorNode newParent) {
-    assert(parent == null);
-    assert(body == null);
-    Expression child = newParent.body;
-    newParent.body = this;
-    this.body = child;
-    child.parent = this;
-    this.parent = newParent;
-  }
-}
-
-/// An expression without a continuation or a subexpression body.
-///
-/// These break straight-line control flow and can be thought of as ending a
-/// basic block.
-abstract class TailExpression extends Expression {
-  Expression get next => null;
-}
-
 /// The base class of things that variables can refer to: primitives,
 /// continuations, function and continuation parameters, etc.
 abstract class Definition<T extends Definition<T>> extends Node {
   // The head of a linked-list of occurrences, in no particular order.
   Reference<T> firstRef;
 
-  bool get hasAtMostOneUse  => firstRef == null || firstRef.next == null;
+  bool get hasAtMostOneUse => firstRef == null || firstRef.next == null;
   bool get hasExactlyOneUse => firstRef != null && firstRef.next == null;
   bool get hasNoUses => firstRef == null;
   bool get hasAtLeastOneUse => firstRef != null;
-  bool get hasMultipleUses  => !hasAtMostOneUse;
+  bool get hasMultipleUses => !hasAtMostOneUse;
 
   void replaceUsesWith(Definition<T> newDefinition) {
     if (newDefinition == this) return;
@@ -198,6 +149,45 @@
   }
 }
 
+/// Operands to invocations and primitives are always variables.  They point to
+/// their definition and are doubly-linked into a list of occurrences.
+class Reference<T extends Definition<T>> {
+  T definition;
+  Reference<T> previous;
+  Reference<T> next;
+
+  /// A pointer to the parent node. Is null until set by optimization passes.
+  Node parent;
+
+  Reference(this.definition) {
+    next = definition.firstRef;
+    if (next != null) next.previous = this;
+    definition.firstRef = this;
+  }
+
+  /// Unlinks this reference from the list of occurrences.
+  void unlink() {
+    if (previous == null) {
+      assert(definition.firstRef == this);
+      definition.firstRef = next;
+    } else {
+      previous.next = next;
+    }
+    if (next != null) next.previous = previous;
+  }
+
+  /// Changes the definition referenced by this object and updates
+  /// the reference chains accordingly.
+  void changeTo(Definition<T> newDefinition) {
+    unlink();
+    previous = null;
+    definition = newDefinition;
+    next = definition.firstRef;
+    if (next != null) next.previous = this;
+    definition.firstRef = this;
+  }
+}
+
 class EffectiveUseIterator extends Iterator<Reference<Primitive>> {
   Reference<Primitive> current;
   Reference<Primitive> next;
@@ -242,6 +232,10 @@
 abstract class Primitive extends Variable<Primitive> {
   Primitive() : super(null);
 
+  /// Returns a bitmask with the non-local side effects and dependencies of
+  /// this primitive, as defined by [Effects].
+  int get effects => Effects.none;
+
   /// True if this primitive has a value that can be used by other expressions.
   bool get hasValue;
 
@@ -260,8 +254,8 @@
   // TODO(johnniwinther): Require source information for all primitives.
   SourceInformation get sourceInformation => null;
 
-  /// If this is a [Refinement], [BoundsCheck] or [ReceiverCheck] node, returns the
-  /// value being refined, the indexable object being checked, or the value
+  /// If this is a [Refinement], [BoundsCheck] or [ReceiverCheck] node, returns
+  /// the value being refined, the indexable object being checked, or the value
   /// that was checked to be non-null, respectively.
   ///
   /// Those instructions all return the corresponding operand directly, and
@@ -343,1374 +337,6 @@
   }
 }
 
-/// A primitive that is generally not safe for elimination, but may be marked
-/// as safe by type propagation
-//
-// TODO(asgerf): Store the flag in a bitmask in [Primitive] and get rid of this
-//               class.
-abstract class UnsafePrimitive extends Primitive {
-  bool isSafeForElimination = false;
-  bool isSafeForReordering = false;
-}
-
-/// Operands to invocations and primitives are always variables.  They point to
-/// their definition and are doubly-linked into a list of occurrences.
-class Reference<T extends Definition<T>> {
-  T definition;
-  Reference<T> previous;
-  Reference<T> next;
-
-  /// A pointer to the parent node. Is null until set by optimization passes.
-  Node parent;
-
-  Reference(this.definition) {
-    next = definition.firstRef;
-    if (next != null) next.previous = this;
-    definition.firstRef = this;
-  }
-
-  /// Unlinks this reference from the list of occurrences.
-  void unlink() {
-    if (previous == null) {
-      assert(definition.firstRef == this);
-      definition.firstRef = next;
-    } else {
-      previous.next = next;
-    }
-    if (next != null) next.previous = previous;
-  }
-
-  /// Changes the definition referenced by this object and updates
-  /// the reference chains accordingly.
-  void changeTo(Definition<T> newDefinition) {
-    unlink();
-    previous = null;
-    definition = newDefinition;
-    next = definition.firstRef;
-    if (next != null) next.previous = this;
-    definition.firstRef = this;
-  }
-}
-
-/// Evaluates a primitive and binds it to variable: `let val x = V in E`.
-///
-/// The bound value is in scope in the body.
-///
-/// During one-pass construction a LetPrim with an empty body is used to
-/// represent the one-hole context `let val x = V in []`.
-class LetPrim extends InteriorExpression {
-  Primitive primitive;
-  Expression body;
-
-  LetPrim(this.primitive, [this.body = null]);
-
-  Expression plug(Expression expr) {
-    assert(body == null);
-    return body = expr;
-  }
-
-  accept(BlockVisitor visitor) => visitor.visitLetPrim(this);
-
-  void setParentPointers() {
-    primitive.parent = this;
-    if (body != null) body.parent = this;
-  }
-}
-
-/// Binding continuations.
-///
-/// let cont k0(v0 ...) = E0
-///          k1(v1 ...) = E1
-///          ...
-///   in E
-///
-/// The bound continuations are in scope in the body and the continuation
-/// parameters are in scope in the respective continuation bodies.
-///
-/// During one-pass construction a LetCont whose first continuation has an empty
-/// body is used to represent the one-hole context
-/// `let cont ... k(v) = [] ... in E`.
-class LetCont extends InteriorExpression {
-  List<Continuation> continuations;
-  Expression body;
-
-  LetCont(Continuation continuation, this.body)
-      : continuations = <Continuation>[continuation];
-
-  LetCont.two(Continuation first, Continuation second, this.body)
-      : continuations = <Continuation>[first, second];
-
-  LetCont.many(this.continuations, this.body);
-
-  Expression plug(Expression expr) {
-    assert(continuations != null &&
-           continuations.isNotEmpty &&
-           continuations.first.body == null);
-    return continuations.first.body = expr;
-  }
-
-  accept(BlockVisitor visitor) => visitor.visitLetCont(this);
-
-  void setParentPointers() {
-    _setParentsOnNodes(continuations, this);
-    if (body != null) body.parent = this;
-  }
-}
-
-// Binding an exception handler.
-//
-// let handler h(v0, v1) = E0 in E1
-//
-// The handler is a two-argument (exception, stack trace) continuation which
-// is implicitly the error continuation of all the code in its body E1.
-// [LetHandler] differs from a [LetCont] binding in that it (1) has the
-// runtime semantics of pushing/popping a handler from the dynamic exception
-// handler stack and (2) it does not have any explicit invocations.
-class LetHandler extends InteriorExpression {
-  Continuation handler;
-  Expression body;
-
-  LetHandler(this.handler, this.body);
-
-  accept(BlockVisitor visitor) => visitor.visitLetHandler(this);
-
-  void setParentPointers() {
-    handler.parent = this;
-    if (body != null) body.parent = this;
-  }
-}
-
-/// Binding mutable variables.
-///
-/// let mutable v = P in E
-///
-/// [MutableVariable]s can be seen as ref cells that are not first-class
-/// values.  They are therefore not [Primitive]s and not bound by [LetPrim]
-/// to prevent unrestricted use of references to them.  During one-pass
-/// construction, a [LetMutable] with an empty body is use to represent the
-/// one-hole context 'let mutable v = P in []'.
-class LetMutable extends InteriorExpression {
-  final MutableVariable variable;
-  final Reference<Primitive> value;
-  Expression body;
-
-  LetMutable(this.variable, Primitive value)
-      : this.value = new Reference<Primitive>(value);
-
-  Expression plug(Expression expr) {
-    return body = expr;
-  }
-
-  accept(BlockVisitor visitor) => visitor.visitLetMutable(this);
-
-  void setParentPointers() {
-    variable.parent = this;
-    value.parent = this;
-    if (body != null) body.parent = this;
-  }
-}
-
-enum CallingConvention {
-  /// JS receiver is the Dart receiver, there are no extra arguments.
-  ///
-  /// This includes cases (e.g., static functions, constructors) where there
-  /// is no receiver.
-  ///
-  /// For example: `foo.bar$1(x)`
-  Normal,
-
-  /// JS receiver is an interceptor, the first argument is the Dart receiver.
-  ///
-  /// For example: `getInterceptor(foo).bar$1(foo, x)`
-  Intercepted,
-
-  /// JS receiver is the Dart receiver, the first argument is a dummy value.
-  ///
-  /// For example: `foo.bar$1(0, x)`
-  DummyIntercepted,
-
-  /// JS receiver is the Dart receiver, there are no extra arguments.
-  ///
-  /// Compiles to a one-shot interceptor, e.g: `J.bar$1(foo, x)`
-  OneShotIntercepted,
-}
-
-/// Base class of function invocations.
-///
-/// This class defines the common interface of function invocations.
-abstract class InvocationPrimitive extends UnsafePrimitive {
-  Reference<Primitive> get receiver => null;
-  List<Reference<Primitive>> get arguments;
-  SourceInformation get sourceInformation;
-
-  Reference<Primitive> get dartReceiverReference => null;
-  Primitive get dartReceiver => dartReceiverReference.definition;
-
-  CallingConvention get callingConvention => CallingConvention.Normal;
-
-  Reference<Primitive> dartArgumentReference(int n) {
-    switch (callingConvention) {
-      case CallingConvention.Normal:
-      case CallingConvention.OneShotIntercepted:
-        return arguments[n];
-
-      case CallingConvention.Intercepted:
-      case CallingConvention.DummyIntercepted:
-        return arguments[n + 1];
-    }
-  }
-
-  Primitive dartArgument(int n) => dartArgumentReference(n).definition;
-
-  int get dartArgumentsLength =>
-      arguments.length -
-      (callingConvention == CallingConvention.Intercepted ||
-          callingConvention == CallingConvention.DummyIntercepted ? 1 : 0);
-}
-
-/// Invoke a static function.
-///
-/// All optional arguments declared by [target] are passed in explicitly, and
-/// occur at the end of [arguments] list, in normalized order.
-///
-/// Discussion:
-/// All information in the [selector] is technically redundant; it will likely
-/// be removed.
-class InvokeStatic extends InvocationPrimitive {
-  final FunctionElement target;
-  final Selector selector;
-  final List<Reference<Primitive>> arguments;
-  final SourceInformation sourceInformation;
-
-  InvokeStatic(this.target,
-               this.selector,
-               List<Primitive> args,
-               [this.sourceInformation])
-      : arguments = _referenceList(args);
-
-  InvokeStatic.byReference(this.target,
-                           this.selector,
-                           this.arguments,
-                           [this.sourceInformation]);
-
-  accept(Visitor visitor) => visitor.visitInvokeStatic(this);
-
-  bool get hasValue => true;
-
-  void setParentPointers() {
-    _setParentsOnList(arguments, this);
-  }
-}
-
-/// Invoke a method on an object.
-///
-/// This includes getters, setters, operators, and index getter/setters.
-///
-/// Tearing off a method is treated like a getter invocation (getters and
-/// tear-offs cannot be distinguished at compile-time).
-///
-/// The [selector] records the names of named arguments. The value of named
-/// arguments occur at the end of the [arguments] list, in normalized order.
-class InvokeMethod extends InvocationPrimitive {
-  Reference<Primitive> receiver;
-  Selector selector;
-  TypeMask mask;
-  final List<Reference<Primitive>> arguments;
-  final SourceInformation sourceInformation;
-
-  CallingConvention callingConvention = CallingConvention.Normal;
-
-  Reference<Primitive> get dartReceiverReference {
-    return callingConvention == CallingConvention.Intercepted
-        ? arguments[0]
-        : receiver;
-  }
-
-  /// If true, it is known that the receiver cannot be `null`.
-  bool receiverIsNotNull = false;
-
-  InvokeMethod(Primitive receiver,
-               this.selector,
-               this.mask,
-               List<Primitive> arguments,
-               {this.sourceInformation,
-                this.callingConvention: CallingConvention.Normal})
-      : this.receiver = new Reference<Primitive>(receiver),
-        this.arguments = _referenceList(arguments);
-
-  accept(Visitor visitor) => visitor.visitInvokeMethod(this);
-
-  bool get hasValue => true;
-
-  void setParentPointers() {
-    receiver.parent = this;
-    _setParentsOnList(arguments, this);
-  }
-}
-
-/// Invoke [target] on [receiver], bypassing dispatch and override semantics.
-///
-/// That is, if [receiver] is an instance of a class that overrides [target]
-/// with a different implementation, the overriding implementation is bypassed
-/// and [target]'s implementation is invoked.
-///
-/// As with [InvokeMethod], this can be used to invoke a method, operator,
-/// getter, setter, or index getter/setter.
-///
-/// If it is known that [target] does not use its receiver argument, then
-/// [receiver] may refer to a null constant primitive. This happens for direct
-/// invocations to intercepted methods, where the effective receiver is instead
-/// passed as a formal parameter.
-///
-/// TODO(sra): Review. A direct call to a method that is mixed into a native
-/// class will still require an explicit argument.
-///
-/// All optional arguments declared by [target] are passed in explicitly, and
-/// occur at the end of [arguments] list, in normalized order.
-class InvokeMethodDirectly extends InvocationPrimitive {
-  Reference<Primitive> receiver;
-  final FunctionElement target;
-  final Selector selector;
-  final List<Reference<Primitive>> arguments;
-  final SourceInformation sourceInformation;
-
-  CallingConvention callingConvention;
-
-  Reference<Primitive> get dartReceiverReference {
-    return callingConvention == CallingConvention.Intercepted
-        ? arguments[0]
-        : receiver;
-  }
-
-  InvokeMethodDirectly(Primitive receiver,
-                       this.target,
-                       this.selector,
-                       List<Primitive> arguments,
-                       this.sourceInformation,
-                       {this.callingConvention: CallingConvention.Normal})
-      : this.receiver = new Reference<Primitive>(receiver),
-        this.arguments = _referenceList(arguments);
-
-  accept(Visitor visitor) => visitor.visitInvokeMethodDirectly(this);
-
-  bool get hasValue => true;
-
-  void setParentPointers() {
-    receiver.parent = this;
-    _setParentsOnList(arguments, this);
-  }
-
-  bool get isConstructorBodyCall => target is ConstructorBodyElement;
-  bool get isTearOff => selector.isGetter && !target.isGetter;
-}
-
-/// Non-const call to a constructor.
-///
-/// The [target] may be a generative constructor (forwarding or normal)
-/// or a non-redirecting factory.
-///
-/// All optional arguments declared by [target] are passed in explicitly, and
-/// occur in the [arguments] list, in normalized order.
-///
-/// Last in the [arguments] list, after the mandatory and optional arguments,
-/// the internal representation of each type argument occurs, unless it could
-/// be determined at build-time that the constructed class has no need for its
-/// runtime type information.
-///
-/// Note that [InvokeConstructor] does it itself allocate an object.
-/// The invoked constructor will do that using [CreateInstance].
-class InvokeConstructor extends InvocationPrimitive {
-  final DartType dartType;
-  final ConstructorElement target;
-  final List<Reference<Primitive>> arguments;
-  final Selector selector;
-  final SourceInformation sourceInformation;
-
-  /// If non-null, this is an allocation site-specific type that is potentially
-  /// better than the inferred return type of [target].
-  ///
-  /// In particular, container type masks depend on the allocation site and
-  /// can therefore not be inferred solely based on the call target.
-  TypeMask allocationSiteType;
-
-  InvokeConstructor(this.dartType,
-                    this.target,
-                    this.selector,
-                    List<Primitive> args,
-                    this.sourceInformation,
-                    {this.allocationSiteType})
-      : arguments = _referenceList(args);
-
-  accept(Visitor visitor) => visitor.visitInvokeConstructor(this);
-
-  bool get hasValue => true;
-
-  void setParentPointers() {
-    _setParentsOnList(arguments, this);
-  }
-}
-
-/// An alias for [value] in a context where the value is known to satisfy
-/// [type].
-///
-/// Refinement nodes are inserted before the type propagator pass and removed
-/// afterwards, so as not to complicate passes that don't reason about types,
-/// but need to reason about value references being identical (i.e. referring
-/// to the same primitive).
-class Refinement extends Primitive {
-  Reference<Primitive> value;
-  final TypeMask refineType;
-
-  Refinement(Primitive value, this.refineType)
-    : value = new Reference<Primitive>(value);
-
-  bool get hasValue => true;
-  bool get isSafeForElimination => false;
-  bool get isSafeForReordering => false;
-
-  accept(Visitor visitor) => visitor.visitRefinement(this);
-
-  Primitive get effectiveDefinition => value.definition.effectiveDefinition;
-
-  Primitive get unrefined => value.definition.unrefined;
-
-  void setParentPointers() {
-    value.parent = this;
-  }
-}
-
-/// Checks that [index] is a valid index on a given indexable [object].
-///
-/// In the simplest form, compiles to the following:
-///
-///     if (index < 0 || index >= object.length)
-///         ThrowIndexOutOfRangeException(object, index);
-///
-/// In the general form, any of the following conditions can be checked:
-///
-///  Lower bound: `index >= 0`
-///  Upper bound: `index < object.length`
-///  Emptiness:   `object.length !== 0`
-///  Integerness: `index >>> 0 === index`
-///
-/// [index] must be an integer unless integerness is checked, and [object] must
-/// refer to null or an indexable object, and [length] must be the length of
-/// [object] at the time of the check.
-///
-/// Returns [object] so the bounds check can be used to restrict code motion.
-/// It is possible to have a bounds check node that performs no checks but
-/// is retained to restrict code motion.
-///
-/// The [index] reference may be null if there are no checks to perform,
-/// and the [length] reference may be null if there is no upper bound or
-/// emptiness check.
-///
-/// If a separate code motion guard for the index is required, e.g. because it
-/// must be known to be non-negative in an operator that does not involve
-/// [object], a [Refinement] can be created for it with the non-negative integer
-/// type.
-class BoundsCheck extends Primitive {
-  final Reference<Primitive> object;
-  Reference<Primitive> index;
-  Reference<Primitive> length;
-  int checks;
-  final SourceInformation sourceInformation;
-
-  /// If true, check that `index >= 0`.
-  bool get hasLowerBoundCheck => checks & LOWER_BOUND != 0;
-
-  /// If true, check that `index < object.length`.
-  bool get hasUpperBoundCheck => checks & UPPER_BOUND != 0;
-
-  /// If true, check that `object.length !== 0`.
-  ///
-  /// Equivalent to a lower bound check with `object.length - 1` as the index,
-  /// but this check is faster.
-  ///
-  /// Although [index] is not used in the condition, it is used to generate
-  /// the thrown error.  Currently it is always `-1` for emptiness checks,
-  /// because that corresponds to `object.length - 1` in the error case.
-  bool get hasEmptinessCheck => checks & EMPTINESS != 0;
-
-  /// If true, check that `index` is an integer.
-  bool get hasIntegerCheck => checks & INTEGER != 0;
-
-  /// True if the [length] is needed to perform the check.
-  bool get lengthUsedInCheck => checks & (UPPER_BOUND | EMPTINESS) != 0;
-
-  bool get hasNoChecks => checks == NONE;
-
-  static const int UPPER_BOUND = 1 << 0;
-  static const int LOWER_BOUND = 1 << 1;
-  static const int EMPTINESS = 1 << 2; // See [hasEmptinessCheck].
-  static const int INTEGER = 1 << 3; // Check if index is an int.
-  static const int BOTH_BOUNDS = UPPER_BOUND | LOWER_BOUND;
-  static const int NONE = 0;
-
-  BoundsCheck(Primitive object, Primitive index, Primitive length,
-      [this.checks = BOTH_BOUNDS, this.sourceInformation])
-      : this.object = new Reference<Primitive>(object),
-        this.index = new Reference<Primitive>(index),
-        this.length = length == null ? null : new Reference<Primitive>(length);
-
-  BoundsCheck.noCheck(Primitive object, [this.sourceInformation])
-      : this.object = new Reference<Primitive>(object),
-        this.checks = NONE;
-
-  accept(Visitor visitor) => visitor.visitBoundsCheck(this);
-
-  void setParentPointers() {
-    object.parent = this;
-    if (index != null) {
-      index.parent = this;
-    }
-    if (length != null) {
-      length.parent = this;
-    }
-  }
-
-  String get checkString {
-    if (hasNoChecks) return 'no-check';
-    return [hasUpperBoundCheck ? 'upper' : null,
-        hasLowerBoundCheck ? 'lower' : null,
-        hasEmptinessCheck ? 'emptiness' : null,
-        hasIntegerCheck ? 'integer' : null,
-        'check']
-        .where((x) => x != null).join('-');
-  }
-
-  bool get isSafeForElimination => checks == NONE;
-  bool get isSafeForReordering => false;
-  bool get hasValue => true; // Can be referenced to restrict code motion.
-
-  Primitive get effectiveDefinition => object.definition.effectiveDefinition;
-}
-
-/// Throw a [NoSuchMethodError] if [value] cannot respond to [selector].
-///
-/// Returns [value] so this can be used to restrict code motion.
-///
-/// The check can take one of three forms:
-///
-///     value.toString;
-///     value.selectorName;
-///     value.selectorName();    (should only be used if check always fails)
-///
-/// The first two forms are used when it is known that only null fails the
-/// check.  Additionally, the check may be guarded by a [condition], allowing
-/// for three more forms:
-///
-///     if (condition) value.toString;          (this form is valid but unused)
-///     if (condition) value.selectorName;
-///     if (condition) value.selectorName();
-///
-/// The condition must be true if and only if the check should fail. It should
-/// ideally be of a form understood by JS engines, e.g. a `typeof` test.
-///
-/// If [useSelector] is false, the first form instead becomes `value.toString;`.
-/// This form is faster when the value is non-null and the accessed property has
-/// been removed by tree shaking.
-///
-/// [selector] may not be one of the selectors implemented by the null object.
-class ReceiverCheck extends Primitive {
-  final Reference<Primitive> value;
-  final Selector selector;
-  final SourceInformation sourceInformation;
-  final Reference<Primitive> condition;
-  final int _flags;
-
-  static const int _USE_SELECTOR = 1 << 0;
-  static const int _NULL_CHECK = 1 << 1;
-
-  /// True if the selector name should be used in the check; otherwise
-  /// `toString` will be used.
-  bool get useSelector => _flags & _USE_SELECTOR != 0;
-
-  /// True if null is the only possible input that cannot respond to [selector].
-  bool get isNullCheck => _flags & _NULL_CHECK != 0;
-
-
-  /// Constructor for creating checks in arbitrary configurations.
-  ///
-  /// Consider using one of the named constructors instead.
-  ///
-  /// [useSelector] and [isNullCheck] are mandatory named arguments.
-  ReceiverCheck(Primitive value, this.selector, this.sourceInformation,
-        {Primitive condition, bool useSelector, bool isNullCheck})
-      : value = new Reference<Primitive>(value),
-        condition = _optionalReference(condition),
-        _flags = (useSelector ? _USE_SELECTOR : 0) |
-                 (isNullCheck ? _NULL_CHECK : 0);
-
-  /// Simplified constructor for building null checks.
-  ///
-  /// Null must be the only possible input value that does not respond to
-  /// [selector].
-  ReceiverCheck.nullCheck(
-        Primitive value,
-        Selector selector,
-        SourceInformation sourceInformation,
-        {Primitive condition})
-      : this(value,
-            selector,
-            sourceInformation,
-            condition: condition,
-            useSelector: condition != null,
-            isNullCheck: true);
-
-  /// Simplified constructor for building the general check of form:
-  ///
-  ///     if (condition) value.selectorName();
-  ///
-  ReceiverCheck.generalCheck(
-        Primitive value,
-        Selector selector,
-        SourceInformation sourceInformation,
-        Primitive condition)
-      : this(value,
-            selector,
-            sourceInformation,
-            condition: condition,
-            useSelector: true,
-            isNullCheck: false);
-
-  bool get isSafeForElimination => false;
-  bool get isSafeForReordering => false;
-  bool get hasValue => true;
-
-  accept(Visitor visitor) => visitor.visitReceiverCheck(this);
-
-  void setParentPointers() {
-    value.parent = this;
-    if (condition != null) {
-      condition.parent = this;
-    }
-  }
-
-  Primitive get effectiveDefinition => value.definition.effectiveDefinition;
-
-  String get nullCheckString => isNullCheck ? 'null-check' : 'general-check';
-  String get useSelectorString => useSelector ? 'use-selector' : 'no-selector';
-  String get flagString => '$nullCheckString $useSelectorString';
-}
-
-/// An "is" type test.
-///
-/// Returns `true` if [value] is an instance of [dartType].
-///
-/// [type] must not be the [Object], `dynamic` or [Null] types (though it might
-/// be a type variable containing one of these types). This design is chosen
-/// to simplify code generation for type tests.
-class TypeTest extends Primitive {
-  Reference<Primitive> value;
-  final DartType dartType;
-
-  /// If [dartType] is an [InterfaceType], this holds the internal
-  /// representation of the type arguments to [dartType]. Since these may
-  /// reference type variables from the enclosing class, they are not constant.
-  ///
-  /// If [dartType] is a [TypeVariableType], this is a singleton list with the
-  /// internal representation of the type held in that type variable.
-  ///
-  /// If [dartType] is a [FunctionType], this is a singleton list with the
-  /// internal representation of that type,
-  ///
-  /// Otherwise the list is empty.
-  final List<Reference<Primitive>> typeArguments;
-
-  TypeTest(Primitive value,
-           this.dartType,
-           List<Primitive> typeArguments)
-      : this.value = new Reference<Primitive>(value),
-        this.typeArguments = _referenceList(typeArguments);
-
-  accept(Visitor visitor) => visitor.visitTypeTest(this);
-
-  bool get hasValue => true;
-  bool get isSafeForElimination => true;
-  bool get isSafeForReordering => true;
-
-  void setParentPointers() {
-    value.parent = this;
-    _setParentsOnList(typeArguments, this);
-  }
-}
-
-/// An "is" type test for a raw type, performed by testing a flag property.
-///
-/// Returns `true` if [interceptor] is for [dartType].
-class TypeTestViaFlag extends Primitive {
-  Reference<Primitive> interceptor;
-  final DartType dartType;
-
-  TypeTestViaFlag(Primitive interceptor, this.dartType)
-      : this.interceptor = new Reference<Primitive>(interceptor);
-
-  accept(Visitor visitor) => visitor.visitTypeTestViaFlag(this);
-
-  bool get hasValue => true;
-  bool get isSafeForElimination => true;
-  bool get isSafeForReordering => true;
-
-  void setParentPointers() {
-    interceptor.parent = this;
-  }
-}
-
-/// An "as" type cast.
-///
-/// If [value] is `null` or is an instance of [type], [continuation] is invoked
-/// with [value] as argument. Otherwise, a [CastError] is thrown.
-///
-/// Discussion:
-/// The parameter to [continuation] is redundant since it will always equal
-/// [value], which is typically in scope in the continuation. However, it might
-/// simplify type propagation, since a better type can be computed for the
-/// continuation parameter without needing flow-sensitive analysis.
-class TypeCast extends UnsafePrimitive {
-  Reference<Primitive> value;
-  final DartType dartType;
-
-  /// See the corresponding field on [TypeTest].
-  final List<Reference<Primitive>> typeArguments;
-
-  TypeCast(Primitive value,
-           this.dartType,
-           List<Primitive> typeArguments)
-      : this.value = new Reference<Primitive>(value),
-        this.typeArguments = _referenceList(typeArguments);
-
-  accept(Visitor visitor) => visitor.visitTypeCast(this);
-
-  bool get hasValue => true;
-
-  void setParentPointers() {
-    value.parent = this;
-    _setParentsOnList(typeArguments, this);
-  }
-}
-
-/// Apply a built-in operator.
-///
-/// It must be known that the arguments have the proper types.
-class ApplyBuiltinOperator extends Primitive {
-  BuiltinOperator operator;
-  List<Reference<Primitive>> arguments;
-  final SourceInformation sourceInformation;
-
-  ApplyBuiltinOperator(this.operator,
-                       List<Primitive> arguments,
-                       this.sourceInformation)
-      : this.arguments = _referenceList(arguments);
-
-  accept(Visitor visitor) => visitor.visitApplyBuiltinOperator(this);
-
-  bool get hasValue => true;
-  bool get isSafeForElimination => true;
-  bool get isSafeForReordering => true;
-
-  void setParentPointers() {
-    _setParentsOnList(arguments, this);
-  }
-}
-
-/// Apply a built-in method.
-///
-/// It must be known that the arguments have the proper types.
-class ApplyBuiltinMethod extends Primitive {
-  BuiltinMethod method;
-  Reference<Primitive> receiver;
-  List<Reference<Primitive>> arguments;
-  final SourceInformation sourceInformation;
-
-  bool receiverIsNotNull;
-
-  ApplyBuiltinMethod(this.method,
-                     Primitive receiver,
-                     List<Primitive> arguments,
-                     this.sourceInformation,
-                     {this.receiverIsNotNull: false})
-      : this.receiver = new Reference<Primitive>(receiver),
-        this.arguments = _referenceList(arguments);
-
-  accept(Visitor visitor) => visitor.visitApplyBuiltinMethod(this);
-
-  bool get hasValue => true;
-  bool get isSafeForElimination => false;
-  bool get isSafeForReordering => false;
-
-  void setParentPointers() {
-    receiver.parent = this;
-    _setParentsOnList(arguments, this);
-  }
-}
-
-/// Throw a value.
-///
-/// Throw is an expression, i.e., it always occurs in tail position with
-/// respect to a body or expression.
-class Throw extends TailExpression {
-  Reference<Primitive> value;
-
-  Throw(Primitive value) : value = new Reference<Primitive>(value);
-
-  accept(BlockVisitor visitor) => visitor.visitThrow(this);
-
-  void setParentPointers() {
-    value.parent = this;
-  }
-}
-
-/// Rethrow
-///
-/// Rethrow can only occur inside a continuation bound by [LetHandler].  It
-/// implicitly throws the exception parameter of the enclosing handler with
-/// the same stack trace as the enclosing handler.
-class Rethrow extends TailExpression {
-  accept(BlockVisitor visitor) => visitor.visitRethrow(this);
-  void setParentPointers() {}
-}
-
-/// An expression that is known to be unreachable.
-///
-/// This can be placed as the body of a call continuation, when the caller is
-/// known never to invoke it, e.g. because the calling expression always throws.
-class Unreachable extends TailExpression {
-  accept(BlockVisitor visitor) => visitor.visitUnreachable(this);
-  void setParentPointers() {}
-}
-
-/// Gets the value from a [MutableVariable].
-///
-/// [MutableVariable]s can be seen as ref cells that are not first-class
-/// values.  A [LetPrim] with a [GetMutable] can then be seen as:
-///
-///   let prim p = ![variable] in [body]
-///
-class GetMutable extends Primitive {
-  final Reference<MutableVariable> variable;
-
-  GetMutable(MutableVariable variable)
-      : this.variable = new Reference<MutableVariable>(variable);
-
-  accept(Visitor visitor) => visitor.visitGetMutable(this);
-
-  bool get hasValue => true;
-  bool get isSafeForElimination => true;
-  bool get isSafeForReordering => false;
-
-  void setParentPointers() {
-    variable.parent = this;
-  }
-}
-
-/// Assign a [MutableVariable].
-///
-/// [MutableVariable]s can be seen as ref cells that are not first-class
-/// values.  This can be seen as a dereferencing assignment:
-///
-///   { [variable] := [value]; [body] }
-class SetMutable extends Primitive {
-  final Reference<MutableVariable> variable;
-  final Reference<Primitive> value;
-
-  SetMutable(MutableVariable variable, Primitive value)
-      : this.variable = new Reference<MutableVariable>(variable),
-        this.value = new Reference<Primitive>(value);
-
-  accept(Visitor visitor) => visitor.visitSetMutable(this);
-
-  bool get hasValue => false;
-  bool get isSafeForElimination => false;
-  bool get isSafeForReordering => false;
-
-  void setParentPointers() {
-    variable.parent = this;
-    value.parent = this;
-  }
-}
-
-/// Invoke a continuation in tail position.
-class InvokeContinuation extends TailExpression {
-  Reference<Continuation> continuation;
-  List<Reference<Primitive>> arguments;
-  SourceInformation sourceInformation;
-
-  // An invocation of a continuation is recursive if it occurs in the body of
-  // the continuation itself.
-  bool isRecursive;
-
-  /// True if this invocation escapes from the body of a [LetHandler]
-  /// (i.e. a try block). Notably, such an invocation cannot be inlined.
-  bool isEscapingTry;
-
-  InvokeContinuation(Continuation cont, List<Primitive> args,
-                     {this.isRecursive: false,
-                      this.isEscapingTry: false,
-                      this.sourceInformation})
-      : continuation = new Reference<Continuation>(cont),
-        arguments = _referenceList(args) {
-    assert(cont.parameters == null || cont.parameters.length == args.length);
-    if (isRecursive) cont.isRecursive = true;
-  }
-
-  /// A continuation invocation whose target and arguments will be filled
-  /// in later.
-  ///
-  /// Used as a placeholder for a jump whose target is not yet created
-  /// (e.g., in the translation of break and continue).
-  InvokeContinuation.uninitialized({this.isRecursive: false,
-                                    this.isEscapingTry: false})
-      : continuation = null,
-        arguments = null,
-        sourceInformation = null;
-
-  accept(BlockVisitor visitor) => visitor.visitInvokeContinuation(this);
-
-  void setParentPointers() {
-    if (continuation != null) continuation.parent = this;
-    if (arguments != null) _setParentsOnList(arguments, this);
-  }
-}
-
-/// Choose between a pair of continuations based on a condition value.
-///
-/// The two continuations must not declare any parameters.
-class Branch extends TailExpression {
-  final Reference<Primitive> condition;
-  final Reference<Continuation> trueContinuation;
-  final Reference<Continuation> falseContinuation;
-
-  /// If true, only the value `true` satisfies the condition. Otherwise, any
-  /// truthy value satisfies the check.
-  ///
-  /// Non-strict checks are preferable when the condition is known to be a
-  /// boolean.
-  bool isStrictCheck;
-
-  Branch(Primitive condition,
-         Continuation trueCont,
-         Continuation falseCont,
-         {bool strict})
-      : this.condition = new Reference<Primitive>(condition),
-        trueContinuation = new Reference<Continuation>(trueCont),
-        falseContinuation = new Reference<Continuation>(falseCont),
-        isStrictCheck = strict {
-    assert(strict != null);
-  }
-
-  Branch.strict(Primitive condition,
-                Continuation trueCont,
-                Continuation falseCont)
-        : this(condition, trueCont, falseCont, strict: true);
-
-  Branch.loose(Primitive condition,
-               Continuation trueCont,
-               Continuation falseCont)
-      : this(condition, trueCont, falseCont, strict: false);
-
-  accept(BlockVisitor visitor) => visitor.visitBranch(this);
-
-  void setParentPointers() {
-    condition.parent = this;
-    trueContinuation.parent = this;
-    falseContinuation.parent = this;
-  }
-}
-
-/// Directly assigns to a field on a given object.
-class SetField extends Primitive {
-  final Reference<Primitive> object;
-  FieldElement field;
-  final Reference<Primitive> value;
-
-  SetField(Primitive object, this.field, Primitive value)
-      : this.object = new Reference<Primitive>(object),
-        this.value = new Reference<Primitive>(value);
-
-  accept(Visitor visitor) => visitor.visitSetField(this);
-
-  bool get hasValue => false;
-  bool get isSafeForElimination => false;
-  bool get isSafeForReordering => false;
-
-  void setParentPointers() {
-    object.parent = this;
-    value.parent = this;
-  }
-}
-
-/// Directly reads from a field on a given object.
-///
-/// The [object] must either be `null` or an object that has [field].
-class GetField extends Primitive {
-  final Reference<Primitive> object;
-  FieldElement field;
-
-  /// True if the object is known not to be null.
-  // TODO(asgerf): This is a placeholder until we agree on how to track
-  //               side effects.
-  bool objectIsNotNull = false;
-
-  GetField(Primitive object, this.field)
-      : this.object = new Reference<Primitive>(object);
-
-  accept(Visitor visitor) => visitor.visitGetField(this);
-
-  bool get hasValue => true;
-  bool get isSafeForElimination => objectIsNotNull;
-  bool get isSafeForReordering => false;
-
-  toString() => 'GetField($field)';
-
-  void setParentPointers() {
-    object.parent = this;
-  }
-}
-
-/// Get the length of a string or native list.
-class GetLength extends Primitive {
-  final Reference<Primitive> object;
-
-  /// True if the object is known not to be null.
-  bool objectIsNotNull = false;
-
-  GetLength(Primitive object) : this.object = new Reference<Primitive>(object);
-
-  bool get hasValue => true;
-  bool get isSafeForElimination => objectIsNotNull;
-  bool get isSafeForReordering => false;
-
-  accept(Visitor v) => v.visitGetLength(this);
-
-  void setParentPointers() {
-    object.parent = this;
-  }
-}
-
-/// Read an entry from an indexable object.
-///
-/// [object] must be null or an indexable object, and [index] must be
-/// an integer where `0 <= index < object.length`.
-class GetIndex extends Primitive {
-  final Reference<Primitive> object;
-  final Reference<Primitive> index;
-
-  /// True if the object is known not to be null.
-  bool objectIsNotNull = false;
-
-  GetIndex(Primitive object, Primitive index)
-      : this.object = new Reference<Primitive>(object),
-        this.index = new Reference<Primitive>(index);
-
-  bool get hasValue => true;
-  bool get isSafeForElimination => objectIsNotNull;
-  bool get isSafeForReordering => false;
-
-  accept(Visitor v) => v.visitGetIndex(this);
-
-  void setParentPointers() {
-    object.parent = this;
-    index.parent = this;
-  }
-}
-
-/// Set an entry on a native list.
-///
-/// [object] must be null or a native list, and [index] must be an integer.
-///
-/// The primitive itself has no value and may not be referenced.
-class SetIndex extends Primitive {
-  final Reference<Primitive> object;
-  final Reference<Primitive> index;
-  final Reference<Primitive> value;
-
-  SetIndex(Primitive object, Primitive index, Primitive value)
-      : this.object = new Reference<Primitive>(object),
-        this.index = new Reference<Primitive>(index),
-        this.value = new Reference<Primitive>(value);
-
-  bool get hasValue => false;
-  bool get isSafeForElimination => false;
-  bool get isSafeForReordering => false;
-
-  accept(Visitor v) => v.visitSetIndex(this);
-
-  void setParentPointers() {
-    object.parent = this;
-    index.parent = this;
-    value.parent = this;
-  }
-}
-
-/// Reads the value of a static field or tears off a static method.
-///
-/// If [GetStatic] is used to load a lazily initialized static field, it must
-/// have been initialized beforehand, and a [witness] must be set to restrict
-/// code motion.
-class GetStatic extends Primitive {
-  /// Can be [FieldElement] or [FunctionElement].
-  final Element element;
-  final SourceInformation sourceInformation;
-
-  /// If reading a lazily initialized field, [witness] must refer to a node
-  /// that initializes the field or always occurs after the field initializer.
-  ///
-  /// The value of the witness is not used.
-  Reference<Primitive> witness;
-
-  GetStatic(this.element, [this.sourceInformation]);
-
-  /// Read a lazily initialized static field that is known to have been
-  /// initialized by [witness] or earlier.
-  GetStatic.witnessed(this.element, Primitive witness, [this.sourceInformation])
-      : witness = witness == null ? null : new Reference<Primitive>(witness);
-
-  accept(Visitor visitor) => visitor.visitGetStatic(this);
-
-  bool get hasValue => true;
-  bool get isSafeForElimination => true;
-  bool get isSafeForReordering {
-    return element is FunctionElement || element.isFinal;
-  }
-
-  void setParentPointers() {
-    if (witness != null) {
-      witness.parent = this;
-    }
-  }
-}
-
-/// Sets the value of a static field.
-class SetStatic extends Primitive {
-  final FieldElement element;
-  final Reference<Primitive> value;
-  final SourceInformation sourceInformation;
-
-  SetStatic(this.element, Primitive value, [this.sourceInformation])
-      : this.value = new Reference<Primitive>(value);
-
-  accept(Visitor visitor) => visitor.visitSetStatic(this);
-
-  bool get hasValue => false;
-  bool get isSafeForElimination => false;
-  bool get isSafeForReordering => false;
-
-  void setParentPointers() {
-    value.parent = this;
-  }
-}
-
-/// Reads the value of a lazily initialized static field.
-///
-/// If the field has not yet been initialized, its initializer is evaluated
-/// and assigned to the field.
-class GetLazyStatic extends UnsafePrimitive {
-  final FieldElement element;
-  final SourceInformation sourceInformation;
-
-  GetLazyStatic(this.element, [this.sourceInformation]);
-
-  accept(Visitor visitor) => visitor.visitGetLazyStatic(this);
-
-  bool get hasValue => true;
-
-  void setParentPointers() {}
-}
-
-/// Creates an object for holding boxed variables captured by a closure.
-class CreateBox extends Primitive {
-  accept(Visitor visitor) => visitor.visitCreateBox(this);
-
-  bool get hasValue => true;
-  bool get isSafeForElimination => true;
-  bool get isSafeForReordering => true;
-
-  void setParentPointers() {}
-}
-
-/// Creates an instance of a class and initializes its fields and runtime type
-/// information.
-class CreateInstance extends Primitive {
-  final ClassElement classElement;
-
-  /// Initial values for the fields on the class.
-  /// The order corresponds to the order of fields on the class.
-  final List<Reference<Primitive>> arguments;
-
-  /// The runtime type information structure which contains the type arguments.
-  ///
-  /// May be `null` to indicate that no type information is needed because the
-  /// compiler determined that the type information for instances of this class
-  /// is not needed at runtime.
-  final Reference<Primitive> typeInformation;
-
-  final SourceInformation sourceInformation;
-
-  CreateInstance(this.classElement, List<Primitive> arguments,
-      Primitive typeInformation,
-      this.sourceInformation)
-      : this.arguments = _referenceList(arguments),
-        this.typeInformation = typeInformation == null
-            ? null
-            : new Reference<Primitive>(typeInformation);
-
-  accept(Visitor visitor) => visitor.visitCreateInstance(this);
-
-  bool get hasValue => true;
-  bool get isSafeForElimination => true;
-  bool get isSafeForReordering => true;
-
-  toString() => 'CreateInstance($classElement)';
-
-  void setParentPointers() {
-    _setParentsOnList(arguments, this);
-    if (typeInformation != null) typeInformation.parent = this;
-  }
-}
-
-/// Obtains the interceptor for the given value.  This is a method table
-/// corresponding to the Dart class of the value.
-///
-/// All values are either intercepted or self-intercepted.  The interceptor for
-/// an "intercepted value" is one of the subclasses of Interceptor.
-/// The interceptor for a "self-intercepted value" is the value itself.
-///
-/// If the input is an intercepted value, and any of its superclasses is in
-/// [interceptedClasses], the method table for the input is returned.
-/// Otherwise, the input itself is returned.
-///
-/// There are thus three significant cases:
-/// - the input is a self-interceptor
-/// - the input is an intercepted value and is caught by [interceptedClasses]
-/// - the input is an intercepted value but is bypassed by [interceptedClasses]
-///
-/// The [flags] field indicates which of the above cases may happen, with
-/// additional special cases for null (which can either by intercepted or
-/// bypassed).
-class Interceptor extends Primitive {
-  final Reference<Primitive> input;
-  final Set<ClassElement> interceptedClasses = new Set<ClassElement>();
-  final SourceInformation sourceInformation;
-
-  Interceptor(Primitive input, this.sourceInformation)
-      : this.input = new Reference<Primitive>(input);
-
-  accept(Visitor visitor) => visitor.visitInterceptor(this);
-
-  bool get hasValue => true;
-  bool get isSafeForElimination => true;
-  bool get isSafeForReordering => true;
-
-  void setParentPointers() {
-    input.parent = this;
-  }
-}
-
-/// Create an instance of [Invocation] for use in a call to `noSuchMethod`.
-class CreateInvocationMirror extends Primitive {
-  final Selector selector;
-  final List<Reference<Primitive>> arguments;
-
-  CreateInvocationMirror(this.selector, List<Primitive> arguments)
-      : this.arguments = _referenceList(arguments);
-
-  accept(Visitor visitor) => visitor.visitCreateInvocationMirror(this);
-
-  bool get hasValue => true;
-  bool get isSafeForElimination => true;
-  bool get isSafeForReordering => true;
-
-  void setParentPointers() {
-    _setParentsOnList(arguments, this);
-  }
-}
-
-class ForeignCode extends UnsafePrimitive {
-  final js.Template codeTemplate;
-  final TypeMask storedType;
-  final List<Reference<Primitive>> arguments;
-  final native.NativeBehavior nativeBehavior;
-  final FunctionElement dependency;
-
-  ForeignCode(this.codeTemplate, this.storedType, List<Primitive> arguments,
-      this.nativeBehavior, {this.dependency})
-      : this.arguments = _referenceList(arguments);
-
-  accept(Visitor visitor) => visitor.visitForeignCode(this);
-
-  bool get hasValue => true;
-
-  void setParentPointers() {
-    _setParentsOnList(arguments, this);
-  }
-
-  bool isNullGuardOnNullFirstArgument() {
-    if (arguments.length < 1) return false;
-    // TODO(sra): Fix NativeThrowBehavior to distinguish MAY from
-    // throws-nsm-on-null-followed-by-MAY and remove
-    // [isNullGuardForFirstArgument].
-    if (nativeBehavior.throwBehavior.isNullNSMGuard) return true;
-    return js.isNullGuardOnFirstArgument(codeTemplate);
-  }
-}
-
-class Constant extends Primitive {
-  final values.ConstantValue value;
-  final SourceInformation sourceInformation;
-
-  Constant(this.value, {this.sourceInformation}) {
-    assert(value != null);
-  }
-
-  accept(Visitor visitor) => visitor.visitConstant(this);
-
-  bool get hasValue => true;
-  bool get isSafeForElimination => true;
-  bool get isSafeForReordering => true;
-
-  void setParentPointers() {}
-}
-
-class LiteralList extends Primitive {
-  /// The List type being created; this is not the type argument.
-  final InterfaceType dartType;
-  final List<Reference<Primitive>> values;
-
-  /// If non-null, this is an allocation site-specific type for the list
-  /// created here.
-  TypeMask allocationSiteType;
-
-  LiteralList(this.dartType, List<Primitive> values, {this.allocationSiteType})
-      : this.values = _referenceList(values);
-
-  accept(Visitor visitor) => visitor.visitLiteralList(this);
-
-  bool get hasValue => true;
-  bool get isSafeForElimination => true;
-  bool get isSafeForReordering => true;
-
-  void setParentPointers() {
-    _setParentsOnList(values, this);
-  }
-}
-
-class Parameter extends Primitive {
-  Parameter(Entity hint) {
-    super.hint = hint;
-  }
-
-  accept(Visitor visitor) => visitor.visitParameter(this);
-
-  String toString() => 'Parameter(${hint == null ? null : hint.name})';
-
-  bool get hasValue => true;
-  bool get isSafeForElimination => true;
-  bool get isSafeForReordering => true;
-
-  void setParentPointers() {}
-}
-
 /// Continuations are normally bound by 'let cont'.  A continuation with one
 /// parameter and no body is used to represent a function's return continuation.
 /// The return continuation is bound by the function, not by 'let cont'.
@@ -1736,15 +362,15 @@
   /// [InvokeContinuation].
   bool get isJoinContinuation {
     return body != null &&
-           parent is! LetHandler &&
-           (firstRef == null || firstRef.parent is InvokeContinuation);
+        parent is! LetHandler &&
+        (firstRef == null || firstRef.parent is InvokeContinuation);
   }
 
   Continuation(this.parameters, {this.isRecursive: false});
 
   Continuation.retrn()
-    : parameters = <Parameter>[new Parameter(null)],
-      isRecursive = false;
+      : parameters = <Parameter>[new Parameter(null)],
+        isRecursive = false;
 
   accept(BlockVisitor visitor) => visitor.visitContinuation(this);
 
@@ -1795,11 +421,8 @@
   final Continuation returnContinuation;
   Expression body;
 
-  FunctionDefinition(this.element,
-      this.thisParameter,
-      this.parameters,
-      this.returnContinuation,
-      this.body);
+  FunctionDefinition(this.element, this.thisParameter, this.parameters,
+      this.returnContinuation, this.body);
 
   accept(BlockVisitor visitor) => visitor.visitFunctionDefinition(this);
 
@@ -1811,17 +434,1174 @@
   }
 }
 
+// ----------------------------------------------------------------------------
+//                            PRIMITIVES
+// ----------------------------------------------------------------------------
+
+class Parameter extends Primitive {
+  Parameter(Entity hint) {
+    super.hint = hint;
+  }
+
+  accept(Visitor visitor) => visitor.visitParameter(this);
+
+  String toString() => 'Parameter(${hint == null ? null : hint.name})';
+
+  bool get hasValue => true;
+  bool get isSafeForElimination => true;
+  bool get isSafeForReordering => true;
+
+  void setParentPointers() {}
+}
+
+/// A primitive that is generally not safe for elimination, but may be marked
+/// as safe by type propagation
+abstract class UnsafePrimitive extends Primitive {
+  int effects = Effects.all;
+  bool isSafeForElimination = false;
+  bool isSafeForReordering = false;
+}
+
+enum CallingConvention {
+  /// JS receiver is the Dart receiver, there are no extra arguments.
+  ///
+  /// This includes cases (e.g., static functions, constructors) where there
+  /// is no receiver.
+  ///
+  /// For example: `foo.bar$1(x)`
+  Normal,
+
+  /// JS receiver is an interceptor, the first argument is the Dart receiver.
+  ///
+  /// For example: `getInterceptor(foo).bar$1(foo, x)`
+  Intercepted,
+
+  /// JS receiver is the Dart receiver, the first argument is a dummy value.
+  ///
+  /// For example: `foo.bar$1(0, x)`
+  DummyIntercepted,
+
+  /// JS receiver is the Dart receiver, there are no extra arguments.
+  ///
+  /// Compiles to a one-shot interceptor, e.g: `J.bar$1(foo, x)`
+  OneShotIntercepted,
+}
+
+/// Base class of function invocations.
+///
+/// This class defines the common interface of function invocations.
+abstract class InvocationPrimitive extends UnsafePrimitive {
+  Reference<Primitive> get receiverRef => null;
+  Primitive get receiver => receiverRef?.definition;
+
+  List<Reference<Primitive>> get argumentRefs;
+  Primitive argument(int n) => argumentRefs[n].definition;
+  Iterable<Primitive> get arguments => _dereferenceList(argumentRefs);
+
+  Reference<Primitive> get dartReceiverRef => null;
+  Primitive get dartReceiver => dartReceiverRef?.definition;
+
+  CallingConvention get callingConvention => CallingConvention.Normal;
+
+  Reference<Primitive> dartArgumentReference(int n) {
+    switch (callingConvention) {
+      case CallingConvention.Normal:
+      case CallingConvention.OneShotIntercepted:
+        return argumentRefs[n];
+
+      case CallingConvention.Intercepted:
+      case CallingConvention.DummyIntercepted:
+        return argumentRefs[n + 1];
+    }
+  }
+
+  Primitive dartArgument(int n) => dartArgumentReference(n).definition;
+
+  int get dartArgumentsLength =>
+      argumentRefs.length -
+      (callingConvention == CallingConvention.Intercepted ||
+          callingConvention == CallingConvention.DummyIntercepted ? 1 : 0);
+
+  SourceInformation get sourceInformation;
+}
+
+/// Invoke a static function.
+///
+/// All optional arguments declared by [target] are passed in explicitly, and
+/// occur at the end of [arguments] list, in normalized order.
+///
+/// Discussion:
+/// All information in the [selector] is technically redundant; it will likely
+/// be removed.
+class InvokeStatic extends InvocationPrimitive {
+  final FunctionElement target;
+  final Selector selector;
+  final List<Reference<Primitive>> argumentRefs;
+  final SourceInformation sourceInformation;
+
+  InvokeStatic(this.target, this.selector, List<Primitive> args,
+      [this.sourceInformation])
+      : argumentRefs = _referenceList(args);
+
+  InvokeStatic.byReference(this.target, this.selector, this.argumentRefs,
+      [this.sourceInformation]);
+
+  accept(Visitor visitor) => visitor.visitInvokeStatic(this);
+
+  bool get hasValue => true;
+
+  void setParentPointers() {
+    _setParentsOnList(argumentRefs, this);
+  }
+}
+
+/// Invoke a method on an object.
+///
+/// This includes getters, setters, operators, and index getter/setters.
+///
+/// Tearing off a method is treated like a getter invocation (getters and
+/// tear-offs cannot be distinguished at compile-time).
+///
+/// The [selector] records the names of named arguments. The value of named
+/// arguments occur at the end of the [arguments] list, in normalized order.
+class InvokeMethod extends InvocationPrimitive {
+  Reference<Primitive> receiverRef;
+  Selector selector;
+  TypeMask mask;
+  final List<Reference<Primitive>> argumentRefs;
+  final SourceInformation sourceInformation;
+
+  CallingConvention callingConvention = CallingConvention.Normal;
+
+  Reference<Primitive> get dartReceiverRef {
+    return callingConvention == CallingConvention.Intercepted
+        ? argumentRefs[0]
+        : receiverRef;
+  }
+
+  InvokeMethod(
+      Primitive receiver, this.selector, this.mask, List<Primitive> arguments,
+      {this.sourceInformation,
+      this.callingConvention: CallingConvention.Normal})
+      : this.receiverRef = new Reference<Primitive>(receiver),
+        this.argumentRefs = _referenceList(arguments);
+
+  accept(Visitor visitor) => visitor.visitInvokeMethod(this);
+
+  bool get hasValue => true;
+
+  void setParentPointers() {
+    receiverRef.parent = this;
+    _setParentsOnList(argumentRefs, this);
+  }
+}
+
+/// Invoke [target] on [receiver], bypassing dispatch and override semantics.
+///
+/// That is, if [receiver] is an instance of a class that overrides [target]
+/// with a different implementation, the overriding implementation is bypassed
+/// and [target]'s implementation is invoked.
+///
+/// As with [InvokeMethod], this can be used to invoke a method, operator,
+/// getter, setter, or index getter/setter.
+///
+/// If it is known that [target] does not use its receiver argument, then
+/// [receiver] may refer to a null constant primitive. This happens for direct
+/// invocations to intercepted methods, where the effective receiver is instead
+/// passed as a formal parameter.
+///
+/// TODO(sra): Review. A direct call to a method that is mixed into a native
+/// class will still require an explicit argument.
+///
+/// All optional arguments declared by [target] are passed in explicitly, and
+/// occur at the end of [arguments] list, in normalized order.
+class InvokeMethodDirectly extends InvocationPrimitive {
+  Reference<Primitive> receiverRef;
+  final FunctionElement target;
+  final Selector selector;
+  final List<Reference<Primitive>> argumentRefs;
+  final SourceInformation sourceInformation;
+
+  CallingConvention callingConvention;
+
+  Reference<Primitive> get dartReceiverRef {
+    return callingConvention == CallingConvention.Intercepted
+        ? argumentRefs[0]
+        : receiverRef;
+  }
+
+  InvokeMethodDirectly(Primitive receiver, this.target, this.selector,
+      List<Primitive> arguments, this.sourceInformation,
+      {this.callingConvention: CallingConvention.Normal})
+      : this.receiverRef = new Reference<Primitive>(receiver),
+        this.argumentRefs = _referenceList(arguments);
+
+  accept(Visitor visitor) => visitor.visitInvokeMethodDirectly(this);
+
+  bool get hasValue => true;
+
+  void setParentPointers() {
+    receiverRef.parent = this;
+    _setParentsOnList(argumentRefs, this);
+  }
+
+  bool get isConstructorBodyCall => target is ConstructorBodyElement;
+  bool get isTearOff => selector.isGetter && !target.isGetter;
+}
+
+/// Non-const call to a constructor.
+///
+/// The [target] may be a generative constructor (forwarding or normal)
+/// or a non-redirecting factory.
+///
+/// All optional arguments declared by [target] are passed in explicitly, and
+/// occur in the [arguments] list, in normalized order.
+///
+/// Last in the [arguments] list, after the mandatory and optional arguments,
+/// the internal representation of each type argument occurs, unless it could
+/// be determined at build-time that the constructed class has no need for its
+/// runtime type information.
+///
+/// Note that [InvokeConstructor] does it itself allocate an object.
+/// The invoked constructor will do that using [CreateInstance].
+class InvokeConstructor extends InvocationPrimitive {
+  final DartType dartType;
+  final ConstructorElement target;
+  final List<Reference<Primitive>> argumentRefs;
+  final Selector selector;
+  final SourceInformation sourceInformation;
+
+  /// If non-null, this is an allocation site-specific type that is potentially
+  /// better than the inferred return type of [target].
+  ///
+  /// In particular, container type masks depend on the allocation site and
+  /// can therefore not be inferred solely based on the call target.
+  TypeMask allocationSiteType;
+
+  InvokeConstructor(this.dartType, this.target, this.selector,
+      List<Primitive> args, this.sourceInformation,
+      {this.allocationSiteType})
+      : argumentRefs = _referenceList(args);
+
+  accept(Visitor visitor) => visitor.visitInvokeConstructor(this);
+
+  bool get hasValue => true;
+
+  void setParentPointers() {
+    _setParentsOnList(argumentRefs, this);
+  }
+}
+
+/// An alias for [value] in a context where the value is known to satisfy
+/// [type].
+///
+/// Refinement nodes are inserted before the type propagator pass and removed
+/// afterwards, so as not to complicate passes that don't reason about types,
+/// but need to reason about value references being identical (i.e. referring
+/// to the same primitive).
+class Refinement extends Primitive {
+  Reference<Primitive> value;
+  final TypeMask refineType;
+
+  Refinement(Primitive value, this.refineType)
+      : value = new Reference<Primitive>(value);
+
+  bool get hasValue => true;
+  bool get isSafeForElimination => false;
+  bool get isSafeForReordering => false;
+
+  accept(Visitor visitor) => visitor.visitRefinement(this);
+
+  Primitive get effectiveDefinition => value.definition.effectiveDefinition;
+
+  Primitive get unrefined => value.definition.unrefined;
+
+  void setParentPointers() {
+    value.parent = this;
+  }
+}
+
+/// Checks that [index] is a valid index on a given indexable [object].
+///
+/// In the simplest form, compiles to the following:
+///
+///     if (index < 0 || index >= object.length)
+///         ThrowIndexOutOfRangeException(object, index);
+///
+/// In the general form, any of the following conditions can be checked:
+///
+///  Lower bound: `index >= 0`
+///  Upper bound: `index < object.length`
+///  Emptiness:   `object.length !== 0`
+///  Integerness: `index >>> 0 === index`
+///
+/// [index] must be an integer unless integerness is checked, and [object] must
+/// refer to null or an indexable object, and [length] must be the length of
+/// [object] at the time of the check.
+///
+/// Returns [object] so the bounds check can be used to restrict code motion.
+/// It is possible to have a bounds check node that performs no checks but
+/// is retained to restrict code motion.
+///
+/// The [index] reference may be null if there are no checks to perform,
+/// and the [length] reference may be null if there is no upper bound or
+/// emptiness check.
+///
+/// If a separate code motion guard for the index is required, e.g. because it
+/// must be known to be non-negative in an operator that does not involve
+/// [object], a [Refinement] can be created for it with the non-negative integer
+/// type.
+class BoundsCheck extends Primitive {
+  final Reference<Primitive> objectRef;
+  Reference<Primitive> indexRef;
+  Reference<Primitive> lengthRef;
+  int checks;
+  final SourceInformation sourceInformation;
+
+  Primitive get object => objectRef.definition;
+  Primitive get index => indexRef?.definition;
+  Primitive get length => lengthRef?.definition;
+
+  /// If true, check that `index >= 0`.
+  bool get hasLowerBoundCheck => checks & LOWER_BOUND != 0;
+
+  /// If true, check that `index < object.length`.
+  bool get hasUpperBoundCheck => checks & UPPER_BOUND != 0;
+
+  /// If true, check that `object.length !== 0`.
+  ///
+  /// Equivalent to a lower bound check with `object.length - 1` as the index,
+  /// but this check is faster.
+  ///
+  /// Although [index] is not used in the condition, it is used to generate
+  /// the thrown error.  Currently it is always `-1` for emptiness checks,
+  /// because that corresponds to `object.length - 1` in the error case.
+  bool get hasEmptinessCheck => checks & EMPTINESS != 0;
+
+  /// If true, check that `index` is an integer.
+  bool get hasIntegerCheck => checks & INTEGER != 0;
+
+  /// True if the [length] is needed to perform the check.
+  bool get lengthUsedInCheck => checks & (UPPER_BOUND | EMPTINESS) != 0;
+
+  bool get hasNoChecks => checks == NONE;
+
+  static const int UPPER_BOUND = 1 << 0;
+  static const int LOWER_BOUND = 1 << 1;
+  static const int EMPTINESS = 1 << 2; // See [hasEmptinessCheck].
+  static const int INTEGER = 1 << 3; // Check if index is an int.
+  static const int BOTH_BOUNDS = UPPER_BOUND | LOWER_BOUND;
+  static const int NONE = 0;
+
+  BoundsCheck(Primitive object, Primitive index, Primitive length,
+      [this.checks = BOTH_BOUNDS, this.sourceInformation])
+      : this.objectRef = new Reference<Primitive>(object),
+        this.indexRef = new Reference<Primitive>(index),
+        this.lengthRef = _optionalReference(length);
+
+  BoundsCheck.noCheck(Primitive object, [this.sourceInformation])
+      : this.objectRef = new Reference<Primitive>(object),
+        this.checks = NONE;
+
+  accept(Visitor visitor) => visitor.visitBoundsCheck(this);
+
+  void setParentPointers() {
+    objectRef.parent = this;
+    if (indexRef != null) {
+      indexRef.parent = this;
+    }
+    if (lengthRef != null) {
+      lengthRef.parent = this;
+    }
+  }
+
+  String get checkString {
+    if (hasNoChecks) return 'no-check';
+    return [
+      hasUpperBoundCheck ? 'upper' : null,
+      hasLowerBoundCheck ? 'lower' : null,
+      hasEmptinessCheck ? 'emptiness' : null,
+      hasIntegerCheck ? 'integer' : null,
+      'check'
+    ].where((x) => x != null).join('-');
+  }
+
+  bool get isSafeForElimination => checks == NONE;
+  bool get isSafeForReordering => false;
+  bool get hasValue => true; // Can be referenced to restrict code motion.
+
+  Primitive get effectiveDefinition => object.effectiveDefinition;
+}
+
+/// Throw a [NoSuchMethodError] if [value] cannot respond to [selector].
+///
+/// Returns [value] so this can be used to restrict code motion.
+///
+/// The check can take one of three forms:
+///
+///     value.toString;
+///     value.selectorName;
+///     value.selectorName();    (should only be used if check always fails)
+///
+/// The first two forms are used when it is known that only null fails the
+/// check.  Additionally, the check may be guarded by a [condition], allowing
+/// for three more forms:
+///
+///     if (condition) value.toString;          (this form is valid but unused)
+///     if (condition) value.selectorName;
+///     if (condition) value.selectorName();
+///
+/// The condition must be true if and only if the check should fail. It should
+/// ideally be of a form understood by JS engines, e.g. a `typeof` test.
+///
+/// If [useSelector] is false, the first form instead becomes `value.toString;`.
+/// This form is faster when the value is non-null and the accessed property has
+/// been removed by tree shaking.
+///
+/// [selector] may not be one of the selectors implemented by the null object.
+class ReceiverCheck extends Primitive {
+  final Reference<Primitive> valueRef;
+  final Selector selector;
+  final SourceInformation sourceInformation;
+  final Reference<Primitive> conditionRef;
+  final int _flags;
+
+  Primitive get value => valueRef.definition;
+  Primitive get condition => conditionRef?.definition;
+
+  static const int _USE_SELECTOR = 1 << 0;
+  static const int _NULL_CHECK = 1 << 1;
+
+  /// True if the selector name should be used in the check; otherwise
+  /// `toString` will be used.
+  bool get useSelector => _flags & _USE_SELECTOR != 0;
+
+  /// True if null is the only possible input that cannot respond to [selector].
+  bool get isNullCheck => _flags & _NULL_CHECK != 0;
+
+  /// Constructor for creating checks in arbitrary configurations.
+  ///
+  /// Consider using one of the named constructors instead.
+  ///
+  /// [useSelector] and [isNullCheck] are mandatory named arguments.
+  ReceiverCheck(Primitive value, this.selector, this.sourceInformation,
+      {Primitive condition, bool useSelector, bool isNullCheck})
+      : valueRef = new Reference<Primitive>(value),
+        conditionRef = _optionalReference(condition),
+        _flags =
+            (useSelector ? _USE_SELECTOR : 0) | (isNullCheck ? _NULL_CHECK : 0);
+
+  /// Simplified constructor for building null checks.
+  ///
+  /// Null must be the only possible input value that does not respond to
+  /// [selector].
+  ReceiverCheck.nullCheck(
+      Primitive value, Selector selector, SourceInformation sourceInformation,
+      {Primitive condition})
+      : this(value, selector, sourceInformation,
+            condition: condition,
+            useSelector: condition != null,
+            isNullCheck: true);
+
+  /// Simplified constructor for building the general check of form:
+  ///
+  ///     if (condition) value.selectorName();
+  ///
+  ReceiverCheck.generalCheck(Primitive value, Selector selector,
+      SourceInformation sourceInformation, Primitive condition)
+      : this(value, selector, sourceInformation,
+            condition: condition, useSelector: true, isNullCheck: false);
+
+  bool get isSafeForElimination => false;
+  bool get isSafeForReordering => false;
+  bool get hasValue => true;
+
+  accept(Visitor visitor) => visitor.visitReceiverCheck(this);
+
+  void setParentPointers() {
+    valueRef.parent = this;
+    if (conditionRef != null) {
+      conditionRef.parent = this;
+    }
+  }
+
+  Primitive get effectiveDefinition => value.effectiveDefinition;
+
+  String get nullCheckString => isNullCheck ? 'null-check' : 'general-check';
+  String get useSelectorString => useSelector ? 'use-selector' : 'no-selector';
+  String get flagString => '$nullCheckString $useSelectorString';
+}
+
+/// An "is" type test.
+///
+/// Returns `true` if [value] is an instance of [dartType].
+///
+/// [type] must not be the [Object], `dynamic` or [Null] types (though it might
+/// be a type variable containing one of these types). This design is chosen
+/// to simplify code generation for type tests.
+class TypeTest extends Primitive {
+  Reference<Primitive> valueRef;
+  final DartType dartType;
+
+  /// If [dartType] is an [InterfaceType], this holds the internal
+  /// representation of the type arguments to [dartType]. Since these may
+  /// reference type variables from the enclosing class, they are not constant.
+  ///
+  /// If [dartType] is a [TypeVariableType], this is a singleton list with the
+  /// internal representation of the type held in that type variable.
+  ///
+  /// If [dartType] is a [FunctionType], this is a singleton list with the
+  /// internal representation of that type,
+  ///
+  /// Otherwise the list is empty.
+  final List<Reference<Primitive>> typeArgumentRefs;
+
+  Primitive get value => valueRef.definition;
+  Primitive typeArgument(int n) => typeArgumentRefs[n].definition;
+  Iterable<Primitive> get typeArguments => _dereferenceList(typeArgumentRefs);
+
+  TypeTest(Primitive value, this.dartType, List<Primitive> typeArguments)
+      : this.valueRef = new Reference<Primitive>(value),
+        this.typeArgumentRefs = _referenceList(typeArguments);
+
+  accept(Visitor visitor) => visitor.visitTypeTest(this);
+
+  bool get hasValue => true;
+  bool get isSafeForElimination => true;
+  bool get isSafeForReordering => true;
+
+  void setParentPointers() {
+    valueRef.parent = this;
+    _setParentsOnList(typeArgumentRefs, this);
+  }
+}
+
+/// An "is" type test for a raw type, performed by testing a flag property.
+///
+/// Returns `true` if [interceptor] is for [dartType].
+class TypeTestViaFlag extends Primitive {
+  Reference<Primitive> interceptorRef;
+  final DartType dartType;
+
+  Primitive get interceptor => interceptorRef.definition;
+
+  TypeTestViaFlag(Primitive interceptor, this.dartType)
+      : this.interceptorRef = new Reference<Primitive>(interceptor);
+
+  accept(Visitor visitor) => visitor.visitTypeTestViaFlag(this);
+
+  bool get hasValue => true;
+  bool get isSafeForElimination => true;
+  bool get isSafeForReordering => true;
+
+  void setParentPointers() {
+    interceptorRef.parent = this;
+  }
+}
+
+/// An "as" type cast.
+///
+/// If [value] is `null` or is an instance of [type], [continuation] is invoked
+/// with [value] as argument. Otherwise, a [CastError] is thrown.
+///
+/// Discussion:
+/// The parameter to [continuation] is redundant since it will always equal
+/// [value], which is typically in scope in the continuation. However, it might
+/// simplify type propagation, since a better type can be computed for the
+/// continuation parameter without needing flow-sensitive analysis.
+class TypeCast extends UnsafePrimitive {
+  Reference<Primitive> valueRef;
+  final DartType dartType;
+
+  /// See the corresponding field on [TypeTest].
+  final List<Reference<Primitive>> typeArgumentRefs;
+
+  Primitive get value => valueRef.definition;
+  Primitive typeArgument(int n) => typeArgumentRefs[n].definition;
+  Iterable<Primitive> get typeArguments => _dereferenceList(typeArgumentRefs);
+
+  TypeCast(Primitive value, this.dartType, List<Primitive> typeArguments)
+      : this.valueRef = new Reference<Primitive>(value),
+        this.typeArgumentRefs = _referenceList(typeArguments);
+
+  accept(Visitor visitor) => visitor.visitTypeCast(this);
+
+  bool get hasValue => true;
+
+  void setParentPointers() {
+    valueRef.parent = this;
+    _setParentsOnList(typeArgumentRefs, this);
+  }
+}
+
+/// Apply a built-in operator.
+///
+/// It must be known that the arguments have the proper types.
+class ApplyBuiltinOperator extends Primitive {
+  BuiltinOperator operator;
+  List<Reference<Primitive>> argumentRefs;
+  final SourceInformation sourceInformation;
+
+  Primitive argument(int n) => argumentRefs[n].definition;
+  Iterable<Primitive> get arguments => _dereferenceList(argumentRefs);
+
+  ApplyBuiltinOperator(
+      this.operator, List<Primitive> arguments, this.sourceInformation)
+      : this.argumentRefs = _referenceList(arguments);
+
+  accept(Visitor visitor) => visitor.visitApplyBuiltinOperator(this);
+
+  bool get hasValue => true;
+  bool get isSafeForElimination => true;
+  bool get isSafeForReordering => true;
+
+  void setParentPointers() {
+    _setParentsOnList(argumentRefs, this);
+  }
+}
+
+/// Apply a built-in method.
+///
+/// It must be known that the arguments have the proper types.
+class ApplyBuiltinMethod extends Primitive {
+  BuiltinMethod method;
+  Reference<Primitive> receiverRef;
+  List<Reference<Primitive>> argumentRefs;
+  final SourceInformation sourceInformation;
+
+  Primitive get receiver => receiverRef.definition;
+  Primitive argument(int n) => argumentRefs[n].definition;
+  Iterable<Primitive> get arguments => _dereferenceList(argumentRefs);
+
+  ApplyBuiltinMethod(this.method, Primitive receiver, List<Primitive> arguments,
+      this.sourceInformation)
+      : this.receiverRef = new Reference<Primitive>(receiver),
+        this.argumentRefs = _referenceList(arguments);
+
+  accept(Visitor visitor) => visitor.visitApplyBuiltinMethod(this);
+
+  bool get hasValue => true;
+  bool get isSafeForElimination => false;
+  bool get isSafeForReordering => false;
+
+  void setParentPointers() {
+    receiverRef.parent = this;
+    _setParentsOnList(argumentRefs, this);
+  }
+
+  int get effects => getEffectsOfBuiltinMethod(method);
+}
+
+/// Gets the value from a [MutableVariable].
+///
+/// [MutableVariable]s can be seen as ref cells that are not first-class
+/// values.  A [LetPrim] with a [GetMutable] can then be seen as:
+///
+///   let prim p = ![variable] in [body]
+///
+class GetMutable extends Primitive {
+  final Reference<MutableVariable> variableRef;
+
+  MutableVariable get variable => variableRef.definition;
+
+  GetMutable(MutableVariable variable)
+      : this.variableRef = new Reference<MutableVariable>(variable);
+
+  accept(Visitor visitor) => visitor.visitGetMutable(this);
+
+  bool get hasValue => true;
+  bool get isSafeForElimination => true;
+  bool get isSafeForReordering => false;
+
+  void setParentPointers() {
+    variableRef.parent = this;
+  }
+}
+
+/// Assign a [MutableVariable].
+///
+/// [MutableVariable]s can be seen as ref cells that are not first-class
+/// values.  This can be seen as a dereferencing assignment:
+///
+///   { [variable] := [value]; [body] }
+class SetMutable extends Primitive {
+  final Reference<MutableVariable> variableRef;
+  final Reference<Primitive> valueRef;
+
+  MutableVariable get variable => variableRef.definition;
+  Primitive get value => valueRef.definition;
+
+  SetMutable(MutableVariable variable, Primitive value)
+      : this.variableRef = new Reference<MutableVariable>(variable),
+        this.valueRef = new Reference<Primitive>(value);
+
+  accept(Visitor visitor) => visitor.visitSetMutable(this);
+
+  bool get hasValue => false;
+  bool get isSafeForElimination => false;
+  bool get isSafeForReordering => false;
+
+  void setParentPointers() {
+    variableRef.parent = this;
+    valueRef.parent = this;
+  }
+}
+
+/// Directly reads from a field on a given object.
+///
+/// The [object] must either be `null` or an object that has [field].
+class GetField extends Primitive {
+  final Reference<Primitive> objectRef;
+  FieldElement field;
+
+  /// True if the field never changes value.
+  final bool isFinal;
+
+  /// True if the object is known not to be null.
+  // TODO(asgerf): This is a placeholder until we agree on how to track
+  //               side effects.
+  bool objectIsNotNull = false;
+
+  Primitive get object => objectRef.definition;
+
+  GetField(Primitive object, this.field, {this.isFinal: false})
+      : this.objectRef = new Reference<Primitive>(object);
+
+  accept(Visitor visitor) => visitor.visitGetField(this);
+
+  bool get hasValue => true;
+  bool get isSafeForElimination => objectIsNotNull;
+  bool get isSafeForReordering => false;
+
+  toString() => 'GetField($field)';
+
+  void setParentPointers() {
+    objectRef.parent = this;
+  }
+
+  int get effects => isFinal ? 0 : Effects.dependsOnInstanceField;
+}
+
+/// Directly assigns to a field on a given object.
+class SetField extends Primitive {
+  final Reference<Primitive> objectRef;
+  FieldElement field;
+  final Reference<Primitive> valueRef;
+
+  Primitive get object => objectRef.definition;
+  Primitive get value => valueRef.definition;
+
+  SetField(Primitive object, this.field, Primitive value)
+      : this.objectRef = new Reference<Primitive>(object),
+        this.valueRef = new Reference<Primitive>(value);
+
+  accept(Visitor visitor) => visitor.visitSetField(this);
+
+  bool get hasValue => false;
+  bool get isSafeForElimination => false;
+  bool get isSafeForReordering => false;
+
+  void setParentPointers() {
+    objectRef.parent = this;
+    valueRef.parent = this;
+  }
+
+  int get effects => Effects.changesInstanceField;
+}
+
+/// Get the length of a string or native list.
+class GetLength extends Primitive {
+  final Reference<Primitive> objectRef;
+
+  /// True if the length of the given object can never change.
+  bool isFinal;
+
+  /// True if the object is known not to be null.
+  bool objectIsNotNull = false;
+
+  Primitive get object => objectRef.definition;
+
+  GetLength(Primitive object, {this.isFinal: false})
+      : this.objectRef = new Reference<Primitive>(object);
+
+  bool get hasValue => true;
+  bool get isSafeForElimination => objectIsNotNull;
+  bool get isSafeForReordering => false;
+
+  accept(Visitor v) => v.visitGetLength(this);
+
+  void setParentPointers() {
+    objectRef.parent = this;
+  }
+
+  int get effects => isFinal ? 0 : Effects.dependsOnIndexableLength;
+}
+
+/// Read an entry from an indexable object.
+///
+/// [object] must be null or an indexable object, and [index] must be
+/// an integer where `0 <= index < object.length`.
+class GetIndex extends Primitive {
+  final Reference<Primitive> objectRef;
+  final Reference<Primitive> indexRef;
+
+  /// True if the object is known not to be null.
+  bool objectIsNotNull = false;
+
+  Primitive get object => objectRef.definition;
+  Primitive get index => indexRef.definition;
+
+  GetIndex(Primitive object, Primitive index)
+      : this.objectRef = new Reference<Primitive>(object),
+        this.indexRef = new Reference<Primitive>(index);
+
+  bool get hasValue => true;
+  bool get isSafeForElimination => objectIsNotNull;
+  bool get isSafeForReordering => false;
+
+  accept(Visitor v) => v.visitGetIndex(this);
+
+  void setParentPointers() {
+    objectRef.parent = this;
+    indexRef.parent = this;
+  }
+
+  int get effects => Effects.dependsOnIndexableContent;
+}
+
+/// Set an entry on a native list.
+///
+/// [object] must be null or a native list, and [index] must be an integer
+/// within the bounds of the indexable object.
+///
+/// [SetIndex] may not be used to alter the length of a JS array.
+///
+/// The primitive itself has no value and may not be referenced.
+class SetIndex extends Primitive {
+  final Reference<Primitive> objectRef;
+  final Reference<Primitive> indexRef;
+  final Reference<Primitive> valueRef;
+
+  Primitive get object => objectRef.definition;
+  Primitive get index => indexRef.definition;
+  Primitive get value => valueRef.definition;
+
+  SetIndex(Primitive object, Primitive index, Primitive value)
+      : this.objectRef = new Reference<Primitive>(object),
+        this.indexRef = new Reference<Primitive>(index),
+        this.valueRef = new Reference<Primitive>(value);
+
+  bool get hasValue => false;
+  bool get isSafeForElimination => false;
+  bool get isSafeForReordering => false;
+
+  accept(Visitor v) => v.visitSetIndex(this);
+
+  void setParentPointers() {
+    objectRef.parent = this;
+    indexRef.parent = this;
+    valueRef.parent = this;
+  }
+
+  int get effects => Effects.changesIndexableContent;
+}
+
+/// Reads the value of a static field or tears off a static method.
+///
+/// If [GetStatic] is used to load a lazily initialized static field, it must
+/// have been initialized beforehand, and a [witness] must be set to restrict
+/// code motion.
+class GetStatic extends Primitive {
+  /// Can be [FieldElement] or [FunctionElement].
+  final Element element;
+  final SourceInformation sourceInformation;
+
+  /// True if the field never changes value.
+  final bool isFinal;
+
+  /// If reading a lazily initialized field, [witness] must refer to a node
+  /// that initializes the field or always occurs after the field initializer.
+  ///
+  /// The value of the witness is not used.
+  Reference<Primitive> witnessRef;
+
+  Primitive get witness => witnessRef.definition;
+
+  GetStatic(this.element, {this.isFinal: false, this.sourceInformation});
+
+  /// Read a lazily initialized static field that is known to have been
+  /// initialized by [witness] or earlier.
+  GetStatic.witnessed(this.element, Primitive witness, {this.sourceInformation})
+      : witnessRef = _optionalReference(witness),
+        isFinal = false;
+
+  accept(Visitor visitor) => visitor.visitGetStatic(this);
+
+  bool get hasValue => true;
+  bool get isSafeForElimination => true;
+  bool get isSafeForReordering => isFinal;
+
+  void setParentPointers() {
+    if (witnessRef != null) {
+      witnessRef.parent = this;
+    }
+  }
+
+  int get effects => isFinal ? 0 : Effects.dependsOnStaticField;
+}
+
+/// Sets the value of a static field.
+class SetStatic extends Primitive {
+  final FieldElement element;
+  final Reference<Primitive> valueRef;
+  final SourceInformation sourceInformation;
+
+  Primitive get value => valueRef.definition;
+
+  SetStatic(this.element, Primitive value, [this.sourceInformation])
+      : this.valueRef = new Reference<Primitive>(value);
+
+  accept(Visitor visitor) => visitor.visitSetStatic(this);
+
+  bool get hasValue => false;
+  bool get isSafeForElimination => false;
+  bool get isSafeForReordering => false;
+
+  void setParentPointers() {
+    valueRef.parent = this;
+  }
+
+  int get effects => Effects.changesStaticField;
+}
+
+/// Reads the value of a lazily initialized static field.
+///
+/// If the field has not yet been initialized, its initializer is evaluated
+/// and assigned to the field.
+class GetLazyStatic extends UnsafePrimitive {
+  final FieldElement element;
+  final SourceInformation sourceInformation;
+
+  /// True if the field never changes value.
+  final bool isFinal;
+
+  GetLazyStatic(this.element, {this.isFinal: false, this.sourceInformation});
+
+  accept(Visitor visitor) => visitor.visitGetLazyStatic(this);
+
+  bool get hasValue => true;
+
+  void setParentPointers() {}
+
+  // TODO(asgerf): Track side effects of lazy field initializers.
+  int get effects => Effects.all;
+}
+
+/// Creates an object for holding boxed variables captured by a closure.
+class CreateBox extends Primitive {
+  accept(Visitor visitor) => visitor.visitCreateBox(this);
+
+  bool get hasValue => true;
+  bool get isSafeForElimination => true;
+  bool get isSafeForReordering => true;
+
+  void setParentPointers() {}
+}
+
+/// Creates an instance of a class and initializes its fields and runtime type
+/// information.
+class CreateInstance extends Primitive {
+  final ClassElement classElement;
+
+  /// Initial values for the fields on the class.
+  /// The order corresponds to the order of fields on the class.
+  final List<Reference<Primitive>> argumentRefs;
+
+  /// The runtime type information structure which contains the type arguments.
+  ///
+  /// May be `null` to indicate that no type information is needed because the
+  /// compiler determined that the type information for instances of this class
+  /// is not needed at runtime.
+  final Reference<Primitive> typeInformationRef;
+
+  final SourceInformation sourceInformation;
+
+  Primitive argument(int n) => argumentRefs[n].definition;
+  Iterable<Primitive> get arguments => _dereferenceList(argumentRefs);
+  Primitive get typeInformation => typeInformationRef?.definition;
+
+  CreateInstance(this.classElement, List<Primitive> arguments,
+      Primitive typeInformation, this.sourceInformation)
+      : this.argumentRefs = _referenceList(arguments),
+        this.typeInformationRef = _optionalReference(typeInformation);
+
+  accept(Visitor visitor) => visitor.visitCreateInstance(this);
+
+  bool get hasValue => true;
+  bool get isSafeForElimination => true;
+  bool get isSafeForReordering => true;
+
+  toString() => 'CreateInstance($classElement)';
+
+  void setParentPointers() {
+    _setParentsOnList(argumentRefs, this);
+    if (typeInformationRef != null) typeInformationRef.parent = this;
+  }
+}
+
+/// Obtains the interceptor for the given value.  This is a method table
+/// corresponding to the Dart class of the value.
+///
+/// All values are either intercepted or self-intercepted.  The interceptor for
+/// an "intercepted value" is one of the subclasses of Interceptor.
+/// The interceptor for a "self-intercepted value" is the value itself.
+///
+/// If the input is an intercepted value, and any of its superclasses is in
+/// [interceptedClasses], the method table for the input is returned.
+/// Otherwise, the input itself is returned.
+///
+/// There are thus three significant cases:
+/// - the input is a self-interceptor
+/// - the input is an intercepted value and is caught by [interceptedClasses]
+/// - the input is an intercepted value but is bypassed by [interceptedClasses]
+///
+/// The [flags] field indicates which of the above cases may happen, with
+/// additional special cases for null (which can either by intercepted or
+/// bypassed).
+class Interceptor extends Primitive {
+  final Reference<Primitive> inputRef;
+  final Set<ClassElement> interceptedClasses = new Set<ClassElement>();
+  final SourceInformation sourceInformation;
+
+  Primitive get input => inputRef.definition;
+
+  Interceptor(Primitive input, this.sourceInformation)
+      : this.inputRef = new Reference<Primitive>(input);
+
+  accept(Visitor visitor) => visitor.visitInterceptor(this);
+
+  bool get hasValue => true;
+  bool get isSafeForElimination => true;
+  bool get isSafeForReordering => true;
+
+  void setParentPointers() {
+    inputRef.parent = this;
+  }
+}
+
+/// Create an instance of [Invocation] for use in a call to `noSuchMethod`.
+class CreateInvocationMirror extends Primitive {
+  final Selector selector;
+  final List<Reference<Primitive>> argumentRefs;
+
+  Primitive argument(int n) => argumentRefs[n].definition;
+  Iterable<Primitive> get arguments => _dereferenceList(argumentRefs);
+
+  CreateInvocationMirror(this.selector, List<Primitive> arguments)
+      : this.argumentRefs = _referenceList(arguments);
+
+  accept(Visitor visitor) => visitor.visitCreateInvocationMirror(this);
+
+  bool get hasValue => true;
+  bool get isSafeForElimination => true;
+  bool get isSafeForReordering => true;
+
+  void setParentPointers() {
+    _setParentsOnList(argumentRefs, this);
+  }
+}
+
+class ForeignCode extends UnsafePrimitive {
+  final js.Template codeTemplate;
+  final TypeMask storedType;
+  final List<Reference<Primitive>> argumentRefs;
+  final native.NativeBehavior nativeBehavior;
+  final FunctionElement dependency;
+
+  Primitive argument(int n) => argumentRefs[n].definition;
+  Iterable<Primitive> get arguments => _dereferenceList(argumentRefs);
+
+  ForeignCode(this.codeTemplate, this.storedType, List<Primitive> arguments,
+      this.nativeBehavior,
+      {this.dependency})
+      : this.argumentRefs = _referenceList(arguments) {
+    effects = Effects.from(nativeBehavior.sideEffects);
+  }
+
+  accept(Visitor visitor) => visitor.visitForeignCode(this);
+
+  bool get hasValue => true;
+
+  void setParentPointers() {
+    _setParentsOnList(argumentRefs, this);
+  }
+
+  bool isNullGuardOnNullFirstArgument() {
+    if (argumentRefs.length < 1) return false;
+    // TODO(sra): Fix NativeThrowBehavior to distinguish MAY from
+    // throws-nsm-on-null-followed-by-MAY and remove
+    // [isNullGuardForFirstArgument].
+    if (nativeBehavior.throwBehavior.isNullNSMGuard) return true;
+    return js.isNullGuardOnFirstArgument(codeTemplate);
+  }
+}
+
+class Constant extends Primitive {
+  final values.ConstantValue value;
+  final SourceInformation sourceInformation;
+
+  Constant(this.value, {this.sourceInformation}) {
+    assert(value != null);
+  }
+
+  accept(Visitor visitor) => visitor.visitConstant(this);
+
+  bool get hasValue => true;
+  bool get isSafeForElimination => true;
+  bool get isSafeForReordering => true;
+
+  void setParentPointers() {}
+}
+
+class LiteralList extends Primitive {
+  /// The List type being created; this is not the type argument.
+  final InterfaceType dartType;
+  final List<Reference<Primitive>> valueRefs;
+
+  /// If non-null, this is an allocation site-specific type for the list
+  /// created here.
+  TypeMask allocationSiteType;
+
+  Primitive value(int n) => valueRefs[n].definition;
+  Iterable<Primitive> get values => _dereferenceList(valueRefs);
+
+  LiteralList(this.dartType, List<Primitive> values, {this.allocationSiteType})
+      : this.valueRefs = _referenceList(values);
+
+  accept(Visitor visitor) => visitor.visitLiteralList(this);
+
+  bool get hasValue => true;
+  bool get isSafeForElimination => true;
+  bool get isSafeForReordering => true;
+
+  void setParentPointers() {
+    _setParentsOnList(valueRefs, this);
+  }
+}
+
 /// Converts the internal representation of a type to a Dart object of type
 /// [Type].
 class ReifyRuntimeType extends Primitive {
   /// Reference to the internal representation of a type (as produced, for
   /// example, by [ReadTypeVariable]).
-  final Reference<Primitive> value;
+  final Reference<Primitive> valueRef;
 
   final SourceInformation sourceInformation;
 
+  Primitive get value => valueRef.definition;
+
   ReifyRuntimeType(Primitive value, this.sourceInformation)
-    : this.value = new Reference<Primitive>(value);
+      : this.valueRef = new Reference<Primitive>(value);
 
   @override
   accept(Visitor visitor) => visitor.visitReifyRuntimeType(this);
@@ -1831,7 +1611,7 @@
   bool get isSafeForReordering => true;
 
   void setParentPointers() {
-    value.parent = this;
+    valueRef.parent = this;
   }
 }
 
@@ -1842,11 +1622,13 @@
 /// used as a Dart value.
 class ReadTypeVariable extends Primitive {
   final TypeVariableType variable;
-  final Reference<Primitive> target;
+  final Reference<Primitive> targetRef;
   final SourceInformation sourceInformation;
 
+  Primitive get target => targetRef.definition;
+
   ReadTypeVariable(this.variable, Primitive target, this.sourceInformation)
-      : this.target = new Reference<Primitive>(target);
+      : this.targetRef = new Reference<Primitive>(target);
 
   @override
   accept(Visitor visitor) => visitor.visitReadTypeVariable(this);
@@ -1856,14 +1638,11 @@
   bool get isSafeForReordering => true;
 
   void setParentPointers() {
-    target.parent = this;
+    targetRef.parent = this;
   }
 }
 
-enum TypeExpressionKind {
-  COMPLETE,
-  INSTANCE
-}
+enum TypeExpressionKind { COMPLETE, INSTANCE }
 
 /// Constructs a representation of a closed or ground-term type (that is, a type
 /// without type variables).
@@ -1918,15 +1697,16 @@
 class TypeExpression extends Primitive {
   final TypeExpressionKind kind;
   final DartType dartType;
-  final List<Reference<Primitive>> arguments;
+  final List<Reference<Primitive>> argumentRefs;
 
-  TypeExpression(this.kind,
-                 this.dartType,
-                 List<Primitive> arguments)
-      : this.arguments = _referenceList(arguments) {
+  Primitive argument(int n) => argumentRefs[n].definition;
+  Iterable<Primitive> get arguments => _dereferenceList(argumentRefs);
+
+  TypeExpression(this.kind, this.dartType, List<Primitive> arguments)
+      : this.argumentRefs = _referenceList(arguments) {
     assert(kind == TypeExpressionKind.INSTANCE
-           ? dartType == (dartType.element as ClassElement).thisType
-           : true);
+        ? dartType == (dartType.element as ClassElement).thisType
+        : true);
   }
 
   @override
@@ -1939,22 +1719,25 @@
   bool get isSafeForReordering => true;
 
   void setParentPointers() {
-    _setParentsOnList(arguments, this);
+    _setParentsOnList(argumentRefs, this);
   }
 
   String get kindAsString {
     switch (kind) {
-      case TypeExpressionKind.COMPLETE: return 'COMPLETE';
-      case TypeExpressionKind.INSTANCE: return 'INSTANCE';
+      case TypeExpressionKind.COMPLETE:
+        return 'COMPLETE';
+      case TypeExpressionKind.INSTANCE:
+        return 'INSTANCE';
     }
   }
 }
 
 class Await extends UnsafePrimitive {
-  final Reference<Primitive> input;
+  final Reference<Primitive> inputRef;
 
-  Await(Primitive input)
-    : this.input = new Reference<Primitive>(input);
+  Primitive get input => inputRef.definition;
+
+  Await(Primitive input) : this.inputRef = new Reference<Primitive>(input);
 
   @override
   accept(Visitor visitor) {
@@ -1964,16 +1747,18 @@
   bool get hasValue => true;
 
   void setParentPointers() {
-    input.parent = this;
+    inputRef.parent = this;
   }
 }
 
 class Yield extends UnsafePrimitive {
-  final Reference<Primitive> input;
+  final Reference<Primitive> inputRef;
   final bool hasStar;
 
+  Primitive get input => inputRef.definition;
+
   Yield(Primitive input, this.hasStar)
-    : this.input = new Reference<Primitive>(input);
+      : this.inputRef = new Reference<Primitive>(input);
 
   @override
   accept(Visitor visitor) {
@@ -1983,24 +1768,336 @@
   bool get hasValue => true;
 
   void setParentPointers() {
-    input.parent = this;
+    inputRef.parent = this;
   }
 }
 
+// ---------------------------------------------------------------------------
+//                            EXPRESSIONS
+// ---------------------------------------------------------------------------
+
+/// An expression that creates new bindings and continues evaluation in
+/// a subexpression.
+///
+/// The interior expressions are [LetPrim], [LetCont], [LetHandler], and
+/// [LetMutable].
+abstract class InteriorExpression extends Expression implements InteriorNode {
+  Expression get next => body;
+
+  /// Removes this expression from its current position in the IR.
+  ///
+  /// The node can be re-inserted elsewhere or remain orphaned.
+  ///
+  /// If orphaned, the caller is responsible for unlinking all references in
+  /// the orphaned node. Use [Reference.unlink] or [Primitive.destroy] for this.
+  void remove() {
+    assert(parent != null);
+    assert(parent.body == this);
+    assert(body.parent == this);
+    parent.body = body;
+    body.parent = parent;
+    parent = null;
+    body = null;
+  }
+
+  /// Inserts this above [node].
+  ///
+  /// This node must be orphaned first.
+  void insertAbove(Expression node) {
+    insertBelow(node.parent);
+  }
+
+  /// Inserts this below [node].
+  ///
+  /// This node must be orphaned first.
+  void insertBelow(InteriorNode newParent) {
+    assert(parent == null);
+    assert(body == null);
+    Expression child = newParent.body;
+    newParent.body = this;
+    this.body = child;
+    child.parent = this;
+    this.parent = newParent;
+  }
+}
+
+/// An expression without a continuation or a subexpression body.
+///
+/// These break straight-line control flow and can be thought of as ending a
+/// basic block.
+abstract class TailExpression extends Expression {
+  Expression get next => null;
+}
+
+/// Evaluates a primitive and binds it to variable: `let val x = V in E`.
+///
+/// The bound value is in scope in the body.
+///
+/// During one-pass construction a LetPrim with an empty body is used to
+/// represent the one-hole context `let val x = V in []`.
+class LetPrim extends InteriorExpression {
+  Primitive primitive;
+  Expression body;
+
+  LetPrim(this.primitive, [this.body = null]);
+
+  Expression plug(Expression expr) {
+    assert(body == null);
+    return body = expr;
+  }
+
+  accept(BlockVisitor visitor) => visitor.visitLetPrim(this);
+
+  void setParentPointers() {
+    primitive.parent = this;
+    if (body != null) body.parent = this;
+  }
+}
+
+/// Binding continuations.
+///
+/// let cont k0(v0 ...) = E0
+///          k1(v1 ...) = E1
+///          ...
+///   in E
+///
+/// The bound continuations are in scope in the body and the continuation
+/// parameters are in scope in the respective continuation bodies.
+///
+/// During one-pass construction a LetCont whose first continuation has an empty
+/// body is used to represent the one-hole context
+/// `let cont ... k(v) = [] ... in E`.
+class LetCont extends InteriorExpression {
+  List<Continuation> continuations;
+  Expression body;
+
+  LetCont(Continuation continuation, this.body)
+      : continuations = <Continuation>[continuation];
+
+  LetCont.two(Continuation first, Continuation second, this.body)
+      : continuations = <Continuation>[first, second];
+
+  LetCont.many(this.continuations, this.body);
+
+  Expression plug(Expression expr) {
+    assert(continuations != null &&
+        continuations.isNotEmpty &&
+        continuations.first.body == null);
+    return continuations.first.body = expr;
+  }
+
+  accept(BlockVisitor visitor) => visitor.visitLetCont(this);
+
+  void setParentPointers() {
+    _setParentsOnNodes(continuations, this);
+    if (body != null) body.parent = this;
+  }
+}
+
+// Binding an exception handler.
+//
+// let handler h(v0, v1) = E0 in E1
+//
+// The handler is a two-argument (exception, stack trace) continuation which
+// is implicitly the error continuation of all the code in its body E1.
+// [LetHandler] differs from a [LetCont] binding in that it (1) has the
+// runtime semantics of pushing/popping a handler from the dynamic exception
+// handler stack and (2) it does not have any explicit invocations.
+class LetHandler extends InteriorExpression {
+  Continuation handler;
+  Expression body;
+
+  LetHandler(this.handler, this.body);
+
+  accept(BlockVisitor visitor) => visitor.visitLetHandler(this);
+
+  void setParentPointers() {
+    handler.parent = this;
+    if (body != null) body.parent = this;
+  }
+}
+
+/// Binding mutable variables.
+///
+/// let mutable v = P in E
+///
+/// [MutableVariable]s can be seen as ref cells that are not first-class
+/// values.  They are therefore not [Primitive]s and not bound by [LetPrim]
+/// to prevent unrestricted use of references to them.  During one-pass
+/// construction, a [LetMutable] with an empty body is use to represent the
+/// one-hole context 'let mutable v = P in []'.
+class LetMutable extends InteriorExpression {
+  final MutableVariable variable;
+  final Reference<Primitive> valueRef;
+  Expression body;
+
+  Primitive get value => valueRef.definition;
+
+  LetMutable(this.variable, Primitive value)
+      : this.valueRef = new Reference<Primitive>(value);
+
+  Expression plug(Expression expr) {
+    return body = expr;
+  }
+
+  accept(BlockVisitor visitor) => visitor.visitLetMutable(this);
+
+  void setParentPointers() {
+    variable.parent = this;
+    valueRef.parent = this;
+    if (body != null) body.parent = this;
+  }
+}
+
+/// Throw a value.
+///
+/// Throw is an expression, i.e., it always occurs in tail position with
+/// respect to a body or expression.
+class Throw extends TailExpression {
+  Reference<Primitive> valueRef;
+
+  Primitive get value => valueRef.definition;
+
+  Throw(Primitive value) : valueRef = new Reference<Primitive>(value);
+
+  accept(BlockVisitor visitor) => visitor.visitThrow(this);
+
+  void setParentPointers() {
+    valueRef.parent = this;
+  }
+}
+
+/// Rethrow
+///
+/// Rethrow can only occur inside a continuation bound by [LetHandler].  It
+/// implicitly throws the exception parameter of the enclosing handler with
+/// the same stack trace as the enclosing handler.
+class Rethrow extends TailExpression {
+  accept(BlockVisitor visitor) => visitor.visitRethrow(this);
+  void setParentPointers() {}
+}
+
+/// An expression that is known to be unreachable.
+///
+/// This can be placed as the body of a call continuation, when the caller is
+/// known never to invoke it, e.g. because the calling expression always throws.
+class Unreachable extends TailExpression {
+  accept(BlockVisitor visitor) => visitor.visitUnreachable(this);
+  void setParentPointers() {}
+}
+
+/// Invoke a continuation in tail position.
+class InvokeContinuation extends TailExpression {
+  Reference<Continuation> continuationRef;
+  List<Reference<Primitive>> argumentRefs;
+  SourceInformation sourceInformation;
+
+  Continuation get continuation => continuationRef.definition;
+  Primitive argument(int n) => argumentRefs[n].definition;
+  Iterable<Primitive> get arguments => _dereferenceList(argumentRefs);
+
+  // An invocation of a continuation is recursive if it occurs in the body of
+  // the continuation itself.
+  bool isRecursive;
+
+  /// True if this invocation escapes from the body of a [LetHandler]
+  /// (i.e. a try block). Notably, such an invocation cannot be inlined.
+  bool isEscapingTry;
+
+  InvokeContinuation(Continuation cont, List<Primitive> args,
+      {this.isRecursive: false,
+      this.isEscapingTry: false,
+      this.sourceInformation})
+      : continuationRef = new Reference<Continuation>(cont),
+        argumentRefs = _referenceList(args) {
+    assert(cont.parameters == null || cont.parameters.length == args.length);
+    if (isRecursive) cont.isRecursive = true;
+  }
+
+  /// A continuation invocation whose target and arguments will be filled
+  /// in later.
+  ///
+  /// Used as a placeholder for a jump whose target is not yet created
+  /// (e.g., in the translation of break and continue).
+  InvokeContinuation.uninitialized(
+      {this.isRecursive: false, this.isEscapingTry: false})
+      : continuationRef = null,
+        argumentRefs = null,
+        sourceInformation = null;
+
+  accept(BlockVisitor visitor) => visitor.visitInvokeContinuation(this);
+
+  void setParentPointers() {
+    if (continuationRef != null) continuationRef.parent = this;
+    if (argumentRefs != null) _setParentsOnList(argumentRefs, this);
+  }
+}
+
+/// Choose between a pair of continuations based on a condition value.
+///
+/// The two continuations must not declare any parameters.
+class Branch extends TailExpression {
+  final Reference<Primitive> conditionRef;
+  final Reference<Continuation> trueContinuationRef;
+  final Reference<Continuation> falseContinuationRef;
+
+  Primitive get condition => conditionRef.definition;
+  Continuation get trueContinuation => trueContinuationRef.definition;
+  Continuation get falseContinuation => falseContinuationRef.definition;
+
+  /// If true, only the value `true` satisfies the condition. Otherwise, any
+  /// truthy value satisfies the check.
+  ///
+  /// Non-strict checks are preferable when the condition is known to be a
+  /// boolean.
+  bool isStrictCheck;
+
+  Branch(Primitive condition, Continuation trueCont, Continuation falseCont,
+      {bool strict})
+      : this.conditionRef = new Reference<Primitive>(condition),
+        trueContinuationRef = new Reference<Continuation>(trueCont),
+        falseContinuationRef = new Reference<Continuation>(falseCont),
+        isStrictCheck = strict {
+    assert(strict != null);
+  }
+
+  Branch.strict(
+      Primitive condition, Continuation trueCont, Continuation falseCont)
+      : this(condition, trueCont, falseCont, strict: true);
+
+  Branch.loose(
+      Primitive condition, Continuation trueCont, Continuation falseCont)
+      : this(condition, trueCont, falseCont, strict: false);
+
+  accept(BlockVisitor visitor) => visitor.visitBranch(this);
+
+  void setParentPointers() {
+    conditionRef.parent = this;
+    trueContinuationRef.parent = this;
+    falseContinuationRef.parent = this;
+  }
+}
+
+// ----------------------------------------------------------------------------
+//                            UTILITY STUFF
+// ----------------------------------------------------------------------------
+
 Reference<Primitive> _reference(Primitive definition) {
   return new Reference<Primitive>(definition);
 }
 
 Reference<Primitive> _optionalReference(Primitive definition) {
-  return definition == null
-      ? null
-      : new Reference<Primitive>(definition);
+  return definition == null ? null : new Reference<Primitive>(definition);
 }
 
 List<Reference<Primitive>> _referenceList(Iterable<Primitive> definitions) {
   return definitions.map((e) => new Reference<Primitive>(e)).toList();
 }
 
+Iterable<Primitive> _dereferenceList(List<Reference<Primitive>> references) {
+  return references.map((ref) => ref.definition);
+}
+
 void _setParentsOnNodes(List<Node> nodes, Node parent) {
   for (Node node in nodes) {
     node.parent = parent;
@@ -2013,6 +2110,10 @@
   }
 }
 
+// ----------------------------------------------------------------------------
+//                                 VISITORS
+// ----------------------------------------------------------------------------
+
 /// Visitor for block-level traversals that do not need to dispatch on
 /// primitives.
 abstract class BlockVisitor<T> {
@@ -2210,47 +2311,47 @@
   visitLetMutable(LetMutable node) {
     processLetMutable(node);
     visit(node.variable);
-    processReference(node.value);
+    processReference(node.valueRef);
     visit(node.body);
   }
 
   processInvokeStatic(InvokeStatic node) {}
   visitInvokeStatic(InvokeStatic node) {
     processInvokeStatic(node);
-    node.arguments.forEach(processReference);
+    node.argumentRefs.forEach(processReference);
   }
 
   processInvokeContinuation(InvokeContinuation node) {}
   visitInvokeContinuation(InvokeContinuation node) {
     processInvokeContinuation(node);
-    processReference(node.continuation);
-    node.arguments.forEach(processReference);
+    processReference(node.continuationRef);
+    node.argumentRefs.forEach(processReference);
   }
 
   processInvokeMethod(InvokeMethod node) {}
   visitInvokeMethod(InvokeMethod node) {
     processInvokeMethod(node);
-    processReference(node.receiver);
-    node.arguments.forEach(processReference);
+    processReference(node.receiverRef);
+    node.argumentRefs.forEach(processReference);
   }
 
   processInvokeMethodDirectly(InvokeMethodDirectly node) {}
   visitInvokeMethodDirectly(InvokeMethodDirectly node) {
     processInvokeMethodDirectly(node);
-    processReference(node.receiver);
-    node.arguments.forEach(processReference);
+    processReference(node.receiverRef);
+    node.argumentRefs.forEach(processReference);
   }
 
   processInvokeConstructor(InvokeConstructor node) {}
   visitInvokeConstructor(InvokeConstructor node) {
     processInvokeConstructor(node);
-    node.arguments.forEach(processReference);
+    node.argumentRefs.forEach(processReference);
   }
 
   processThrow(Throw node) {}
   visitThrow(Throw node) {
     processThrow(node);
-    processReference(node.value);
+    processReference(node.valueRef);
   }
 
   processRethrow(Rethrow node) {}
@@ -2261,36 +2362,36 @@
   processBranch(Branch node) {}
   visitBranch(Branch node) {
     processBranch(node);
-    processReference(node.trueContinuation);
-    processReference(node.falseContinuation);
-    processReference(node.condition);
+    processReference(node.trueContinuationRef);
+    processReference(node.falseContinuationRef);
+    processReference(node.conditionRef);
   }
 
   processTypeCast(TypeCast node) {}
   visitTypeCast(TypeCast node) {
     processTypeCast(node);
-    processReference(node.value);
-    node.typeArguments.forEach(processReference);
+    processReference(node.valueRef);
+    node.typeArgumentRefs.forEach(processReference);
   }
 
   processTypeTest(TypeTest node) {}
   visitTypeTest(TypeTest node) {
     processTypeTest(node);
-    processReference(node.value);
-    node.typeArguments.forEach(processReference);
+    processReference(node.valueRef);
+    node.typeArgumentRefs.forEach(processReference);
   }
 
   processTypeTestViaFlag(TypeTestViaFlag node) {}
   visitTypeTestViaFlag(TypeTestViaFlag node) {
     processTypeTestViaFlag(node);
-    processReference(node.interceptor);
+    processReference(node.interceptorRef);
   }
 
   processSetMutable(SetMutable node) {}
   visitSetMutable(SetMutable node) {
     processSetMutable(node);
-    processReference(node.variable);
-    processReference(node.value);
+    processReference(node.variableRef);
+    processReference(node.valueRef);
   }
 
   processGetLazyStatic(GetLazyStatic node) {}
@@ -2301,11 +2402,11 @@
   processLiteralList(LiteralList node) {}
   visitLiteralList(LiteralList node) {
     processLiteralList(node);
-    node.values.forEach(processReference);
+    node.valueRefs.forEach(processReference);
   }
 
   processConstant(Constant node) {}
-  visitConstant(Constant node)  {
+  visitConstant(Constant node) {
     processConstant(node);
   }
 
@@ -2317,7 +2418,7 @@
   processGetMutable(GetMutable node) {}
   visitGetMutable(GetMutable node) {
     processGetMutable(node);
-    processReference(node.variable);
+    processReference(node.variableRef);
   }
 
   processParameter(Parameter node) {}
@@ -2328,41 +2429,43 @@
   processInterceptor(Interceptor node) {}
   visitInterceptor(Interceptor node) {
     processInterceptor(node);
-    processReference(node.input);
+    processReference(node.inputRef);
   }
 
   processCreateInstance(CreateInstance node) {}
   visitCreateInstance(CreateInstance node) {
     processCreateInstance(node);
-    node.arguments.forEach(processReference);
-    if (node.typeInformation != null) processReference(node.typeInformation);
+    node.argumentRefs.forEach(processReference);
+    if (node.typeInformationRef != null) {
+      processReference(node.typeInformationRef);
+    }
   }
 
   processSetField(SetField node) {}
   visitSetField(SetField node) {
     processSetField(node);
-    processReference(node.object);
-    processReference(node.value);
+    processReference(node.objectRef);
+    processReference(node.valueRef);
   }
 
   processGetField(GetField node) {}
   visitGetField(GetField node) {
     processGetField(node);
-    processReference(node.object);
+    processReference(node.objectRef);
   }
 
   processGetStatic(GetStatic node) {}
   visitGetStatic(GetStatic node) {
     processGetStatic(node);
-    if (node.witness != null) {
-      processReference(node.witness);
+    if (node.witnessRef != null) {
+      processReference(node.witnessRef);
     }
   }
 
   processSetStatic(SetStatic node) {}
   visitSetStatic(SetStatic node) {
     processSetStatic(node);
-    processReference(node.value);
+    processReference(node.valueRef);
   }
 
   processCreateBox(CreateBox node) {}
@@ -2373,44 +2476,44 @@
   processReifyRuntimeType(ReifyRuntimeType node) {}
   visitReifyRuntimeType(ReifyRuntimeType node) {
     processReifyRuntimeType(node);
-    processReference(node.value);
+    processReference(node.valueRef);
   }
 
   processReadTypeVariable(ReadTypeVariable node) {}
   visitReadTypeVariable(ReadTypeVariable node) {
     processReadTypeVariable(node);
-    processReference(node.target);
+    processReference(node.targetRef);
   }
 
   processTypeExpression(TypeExpression node) {}
   visitTypeExpression(TypeExpression node) {
     processTypeExpression(node);
-    node.arguments.forEach(processReference);
+    node.argumentRefs.forEach(processReference);
   }
 
   processCreateInvocationMirror(CreateInvocationMirror node) {}
   visitCreateInvocationMirror(CreateInvocationMirror node) {
     processCreateInvocationMirror(node);
-    node.arguments.forEach(processReference);
+    node.argumentRefs.forEach(processReference);
   }
 
   processApplyBuiltinOperator(ApplyBuiltinOperator node) {}
   visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
     processApplyBuiltinOperator(node);
-    node.arguments.forEach(processReference);
+    node.argumentRefs.forEach(processReference);
   }
 
   processApplyBuiltinMethod(ApplyBuiltinMethod node) {}
   visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
     processApplyBuiltinMethod(node);
-    processReference(node.receiver);
-    node.arguments.forEach(processReference);
+    processReference(node.receiverRef);
+    node.argumentRefs.forEach(processReference);
   }
 
   processForeignCode(ForeignCode node) {}
   visitForeignCode(ForeignCode node) {
     processForeignCode(node);
-    node.arguments.forEach(processReference);
+    node.argumentRefs.forEach(processReference);
   }
 
   processUnreachable(Unreachable node) {}
@@ -2421,34 +2524,34 @@
   processAwait(Await node) {}
   visitAwait(Await node) {
     processAwait(node);
-    processReference(node.input);
+    processReference(node.inputRef);
   }
 
   processYield(Yield node) {}
   visitYield(Yield node) {
     processYield(node);
-    processReference(node.input);
+    processReference(node.inputRef);
   }
 
   processGetLength(GetLength node) {}
   visitGetLength(GetLength node) {
     processGetLength(node);
-    processReference(node.object);
+    processReference(node.objectRef);
   }
 
   processGetIndex(GetIndex node) {}
   visitGetIndex(GetIndex node) {
     processGetIndex(node);
-    processReference(node.object);
-    processReference(node.index);
+    processReference(node.objectRef);
+    processReference(node.indexRef);
   }
 
   processSetIndex(SetIndex node) {}
   visitSetIndex(SetIndex node) {
     processSetIndex(node);
-    processReference(node.object);
-    processReference(node.index);
-    processReference(node.value);
+    processReference(node.objectRef);
+    processReference(node.indexRef);
+    processReference(node.valueRef);
   }
 
   processRefinement(Refinement node) {}
@@ -2460,21 +2563,21 @@
   processBoundsCheck(BoundsCheck node) {}
   visitBoundsCheck(BoundsCheck node) {
     processBoundsCheck(node);
-    processReference(node.object);
-    if (node.index != null) {
-      processReference(node.index);
+    processReference(node.objectRef);
+    if (node.indexRef != null) {
+      processReference(node.indexRef);
     }
-    if (node.length != null) {
-      processReference(node.length);
+    if (node.lengthRef != null) {
+      processReference(node.lengthRef);
     }
   }
 
   processNullCheck(ReceiverCheck node) {}
   visitReceiverCheck(ReceiverCheck node) {
     processNullCheck(node);
-    processReference(node.value);
-    if (node.condition != null) {
-      processReference(node.condition);
+    processReference(node.valueRef);
+    if (node.conditionRef != null) {
+      processReference(node.conditionRef);
     }
   }
 }
@@ -2570,7 +2673,7 @@
   Expression traverseLetMutable(LetMutable node) {
     processLetMutable(node);
     visit(node.variable);
-    processReference(node.value);
+    processReference(node.valueRef);
     return node.body;
   }
 
@@ -2636,12 +2739,16 @@
   /// Get the copy of a [Reference]'s definition from the map.
   Definition getCopy(Reference reference) => _copies[reference.definition];
 
+  /// Get the copy of a [Reference]'s definition from the map.
+  Definition getCopyOrNull(Reference reference) =>
+      reference == null ? null : getCopy(reference);
+
   /// Map a list of [Reference]s to the list of their definition's copies.
   List<Definition> getList(List<Reference> list) => list.map(getCopy).toList();
 
   /// Copy a non-[Continuation] [Definition].
   Definition copy(Definition node) {
-    assert (node is! Continuation);
+    assert(node is! Continuation);
     return putCopy(node, visit(node));
   }
 
@@ -2660,65 +2767,67 @@
   visitContinuation(Continuation node) {}
 
   Definition visitInvokeStatic(InvokeStatic node) {
-    return new InvokeStatic(node.target, node.selector, getList(node.arguments),
-        node.sourceInformation);
+    return new InvokeStatic(node.target, node.selector,
+        getList(node.argumentRefs), node.sourceInformation);
   }
 
   Definition visitInvokeMethod(InvokeMethod node) {
-    return new InvokeMethod(getCopy(node.receiver), node.selector, node.mask,
-        getList(node.arguments),
+    return new InvokeMethod(getCopy(node.receiverRef), node.selector, node.mask,
+        getList(node.argumentRefs),
         sourceInformation: node.sourceInformation,
         callingConvention: node.callingConvention);
   }
 
   Definition visitInvokeMethodDirectly(InvokeMethodDirectly node) {
-    return new InvokeMethodDirectly(getCopy(node.receiver), node.target,
-        node.selector,
-        getList(node.arguments),
-        node.sourceInformation,
+    return new InvokeMethodDirectly(getCopy(node.receiverRef), node.target,
+        node.selector, getList(node.argumentRefs), node.sourceInformation,
         callingConvention: node.callingConvention);
   }
 
   Definition visitInvokeConstructor(InvokeConstructor node) {
-    return new InvokeConstructor(node.dartType, node.target, node.selector,
-        getList(node.arguments),
-        node.sourceInformation)
-        ..allocationSiteType = node.allocationSiteType;
+    return new InvokeConstructor(
+        node.dartType,
+        node.target,
+        node.selector,
+        getList(node.argumentRefs),
+        node.sourceInformation)..allocationSiteType = node.allocationSiteType;
   }
 
   Definition visitTypeCast(TypeCast node) {
-    return new TypeCast(getCopy(node.value), node.dartType,
-        getList(node.typeArguments));
+    return new TypeCast(
+        getCopy(node.valueRef), node.dartType, getList(node.typeArgumentRefs));
   }
 
   Definition visitSetMutable(SetMutable node) {
-    return new SetMutable(getCopy(node.variable), getCopy(node.value));
+    return new SetMutable(getCopy(node.variableRef), getCopy(node.valueRef));
   }
 
   Definition visitSetStatic(SetStatic node) {
-    return new SetStatic(node.element, getCopy(node.value),
-        node.sourceInformation);
+    return new SetStatic(
+        node.element, getCopy(node.valueRef), node.sourceInformation);
   }
 
   Definition visitSetField(SetField node) {
-    return new SetField(getCopy(node.object), node.field, getCopy(node.value));
+    return new SetField(
+        getCopy(node.objectRef), node.field, getCopy(node.valueRef));
   }
 
   Definition visitGetLazyStatic(GetLazyStatic node) {
-    return new GetLazyStatic(node.element, node.sourceInformation);
+    return new GetLazyStatic(node.element,
+        isFinal: node.isFinal, sourceInformation: node.sourceInformation);
   }
 
   Definition visitAwait(Await node) {
-    return new Await(getCopy(node.input));
+    return new Await(getCopy(node.inputRef));
   }
 
   Definition visitYield(Yield node) {
-    return new Yield(getCopy(node.input), node.hasStar);
+    return new Yield(getCopy(node.inputRef), node.hasStar);
   }
 
   Definition visitLiteralList(LiteralList node) {
-    return new LiteralList(node.dartType, getList(node.values))
-        ..allocationSiteType = node.allocationSiteType;
+    return new LiteralList(node.dartType, getList(node.valueRefs))
+      ..allocationSiteType = node.allocationSiteType;
   }
 
   Definition visitConstant(Constant node) {
@@ -2726,7 +2835,7 @@
   }
 
   Definition visitGetMutable(GetMutable node) {
-    return new GetMutable(getCopy(node.variable));
+    return new GetMutable(getCopy(node.variableRef));
   }
 
   Definition visitParameter(Parameter node) {
@@ -2738,24 +2847,28 @@
   }
 
   Definition visitGetStatic(GetStatic node) {
-    return new GetStatic(node.element, node.sourceInformation);
+    if (node.witnessRef != null) {
+      return new GetStatic.witnessed(node.element, getCopy(node.witnessRef),
+          sourceInformation: node.sourceInformation);
+    } else {
+      return new GetStatic(node.element,
+          isFinal: node.isFinal, sourceInformation: node.sourceInformation);
+    }
   }
 
   Definition visitInterceptor(Interceptor node) {
-    return new Interceptor(getCopy(node.input), node.sourceInformation)
-        ..interceptedClasses.addAll(node.interceptedClasses);
+    return new Interceptor(getCopy(node.inputRef), node.sourceInformation)
+      ..interceptedClasses.addAll(node.interceptedClasses);
   }
 
   Definition visitCreateInstance(CreateInstance node) {
-    return new CreateInstance(
-        node.classElement,
-        getList(node.arguments),
-        node.typeInformation == null ? null : getCopy(node.typeInformation),
-        node.sourceInformation);
+    return new CreateInstance(node.classElement, getList(node.argumentRefs),
+        getCopyOrNull(node.typeInformationRef), node.sourceInformation);
   }
 
   Definition visitGetField(GetField node) {
-    return new GetField(getCopy(node.object), node.field);
+    return new GetField(getCopy(node.objectRef), node.field,
+        isFinal: node.isFinal);
   }
 
   Definition visitCreateBox(CreateBox node) {
@@ -2763,55 +2876,54 @@
   }
 
   Definition visitReifyRuntimeType(ReifyRuntimeType node) {
-    return new ReifyRuntimeType(getCopy(node.value), node.sourceInformation);
+    return new ReifyRuntimeType(getCopy(node.valueRef), node.sourceInformation);
   }
 
   Definition visitReadTypeVariable(ReadTypeVariable node) {
-    return new ReadTypeVariable(node.variable, getCopy(node.target),
-        node.sourceInformation);
+    return new ReadTypeVariable(
+        node.variable, getCopy(node.targetRef), node.sourceInformation);
   }
 
   Definition visitTypeExpression(TypeExpression node) {
     return new TypeExpression(
-        node.kind, node.dartType, getList(node.arguments));
+        node.kind, node.dartType, getList(node.argumentRefs));
   }
 
   Definition visitCreateInvocationMirror(CreateInvocationMirror node) {
-    return new CreateInvocationMirror(node.selector, getList(node.arguments));
+    return new CreateInvocationMirror(
+        node.selector, getList(node.argumentRefs));
   }
 
   Definition visitTypeTest(TypeTest node) {
-    return new TypeTest(getCopy(node.value), node.dartType,
-        getList(node.typeArguments));
+    return new TypeTest(
+        getCopy(node.valueRef), node.dartType, getList(node.typeArgumentRefs));
   }
 
   Definition visitTypeTestViaFlag(TypeTestViaFlag node) {
-    return new TypeTestViaFlag(getCopy(node.interceptor), node.dartType);
+    return new TypeTestViaFlag(getCopy(node.interceptorRef), node.dartType);
   }
 
   Definition visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
-    return new ApplyBuiltinOperator(node.operator, getList(node.arguments),
-        node.sourceInformation);
+    return new ApplyBuiltinOperator(
+        node.operator, getList(node.argumentRefs), node.sourceInformation);
   }
 
   Definition visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
-    return new ApplyBuiltinMethod(node.method, getCopy(node.receiver),
-        getList(node.arguments),
-        node.sourceInformation,
-        receiverIsNotNull: node.receiverIsNotNull);
+    return new ApplyBuiltinMethod(node.method, getCopy(node.receiverRef),
+        getList(node.argumentRefs), node.sourceInformation);
   }
 
   Definition visitGetLength(GetLength node) {
-    return new GetLength(getCopy(node.object));
+    return new GetLength(getCopy(node.objectRef), isFinal: node.isFinal);
   }
 
   Definition visitGetIndex(GetIndex node) {
-    return new GetIndex(getCopy(node.object), getCopy(node.index));
+    return new GetIndex(getCopy(node.objectRef), getCopy(node.indexRef));
   }
 
   Definition visitSetIndex(SetIndex node) {
-    return new SetIndex(getCopy(node.object), getCopy(node.index),
-        getCopy(node.value));
+    return new SetIndex(getCopy(node.objectRef), getCopy(node.indexRef),
+        getCopy(node.valueRef));
   }
 
   Definition visitRefinement(Refinement node) {
@@ -2820,29 +2932,25 @@
 
   Definition visitBoundsCheck(BoundsCheck node) {
     if (node.hasNoChecks) {
-      return new BoundsCheck.noCheck(getCopy(node.object),
-          node.sourceInformation);
+      return new BoundsCheck.noCheck(
+          getCopy(node.objectRef), node.sourceInformation);
     } else {
-      return new BoundsCheck(getCopy(node.object), getCopy(node.index),
-          node.length == null ? null : getCopy(node.length),
-          node.checks,
-          node.sourceInformation);
+      return new BoundsCheck(getCopy(node.objectRef), getCopy(node.indexRef),
+          getCopyOrNull(node.lengthRef), node.checks, node.sourceInformation);
     }
   }
 
   Definition visitReceiverCheck(ReceiverCheck node) {
-    return new ReceiverCheck(getCopy(node.value),
-        node.selector,
-        node.sourceInformation,
-        condition: node.condition == null ? null : getCopy(node.condition),
+    return new ReceiverCheck(
+        getCopy(node.valueRef), node.selector, node.sourceInformation,
+        condition: getCopyOrNull(node.conditionRef),
         useSelector: node.useSelector,
         isNullCheck: node.isNullCheck);
   }
 
   Definition visitForeignCode(ForeignCode node) {
     return new ForeignCode(node.codeTemplate, node.storedType,
-        getList(node.arguments),
-        node.nativeBehavior,
+        getList(node.argumentRefs), node.nativeBehavior,
         dependency: node.dependency);
   }
 }
@@ -2909,15 +3017,12 @@
     // copied.
     Parameter returnParameter =
         _definitions.copy(node.returnContinuation.parameters.first);
-    Continuation returnContinuation = _copies[node.returnContinuation] =
-        new Continuation([returnParameter]);
+    Continuation returnContinuation =
+        _copies[node.returnContinuation] = new Continuation([returnParameter]);
 
     visit(node.body);
-    FunctionDefinition copy = new FunctionDefinition(node.element,
-        thisParameter,
-        parameters,
-        returnContinuation,
-        _first);
+    FunctionDefinition copy = new FunctionDefinition(
+        node.element, thisParameter, parameters, returnContinuation, _first);
     _first = _current = null;
     return copy;
   }
@@ -2940,9 +3045,8 @@
     // Continuations are copied where they are bound, before processing
     // expressions in the scope of their binding.
     push(node.handler);
-    Continuation handler = _copies[node.handler] =
-        new Continuation(node.handler.parameters.map(_definitions.copy)
-            .toList());
+    Continuation handler = _copies[node.handler] = new Continuation(
+        node.handler.parameters.map(_definitions.copy).toList());
     plug(new LetHandler(handler, null));
     return node.body;
   }
@@ -2953,23 +3057,23 @@
   }
 
   Expression traverseLetMutable(LetMutable node) {
-    plug(new LetMutable(_definitions.copy(node.variable),
-        _definitions.getCopy(node.value)));
+    plug(new LetMutable(
+        _definitions.copy(node.variable), _definitions.getCopy(node.valueRef)));
     return node.body;
   }
 
   // Tail expressions do not have references, so we do not need to map them
   // to their copies.
   visitInvokeContinuation(InvokeContinuation node) {
-    plug(new InvokeContinuation(_copies[node.continuation.definition],
-        _definitions.getList(node.arguments),
+    plug(new InvokeContinuation(
+        _copies[node.continuation], _definitions.getList(node.argumentRefs),
         isRecursive: node.isRecursive,
         isEscapingTry: node.isEscapingTry,
         sourceInformation: node.sourceInformation));
   }
 
   visitThrow(Throw node) {
-    plug(new Throw(_definitions.getCopy(node.value)));
+    plug(new Throw(_definitions.getCopy(node.valueRef)));
   }
 
   visitRethrow(Rethrow node) {
@@ -2977,10 +3081,10 @@
   }
 
   visitBranch(Branch node) {
-    plug(new Branch.loose(_definitions.getCopy(node.condition),
-        _copies[node.trueContinuation.definition],
-        _copies[node.falseContinuation.definition])
-      ..isStrictCheck = node.isStrictCheck);
+    plug(new Branch.loose(
+        _definitions.getCopy(node.conditionRef),
+        _copies[node.trueContinuation],
+        _copies[node.falseContinuation])..isStrictCheck = node.isStrictCheck);
   }
 
   visitUnreachable(Unreachable node) {
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart
index 952f881..4c39e16 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart
@@ -170,7 +170,7 @@
 
   String visitLetMutable(LetMutable node) {
     String name = visit(node.variable);
-    String value = access(node.value);
+    String value = access(node.valueRef);
     String body = indentBlock(() => visit(node.body));
     return '$indentation(LetMutable ($name $value)\n$body)';
   }
@@ -200,22 +200,22 @@
 
   String visitInvokeStatic(InvokeStatic node) {
     String name = node.target.name;
-    String args = formatArguments(node.selector.callStructure, node.arguments);
+    String args = formatArguments(node.selector.callStructure, node.argumentRefs);
     return '(InvokeStatic $name $args)';
   }
 
   String visitInvokeMethod(InvokeMethod node) {
     String name = node.selector.name;
-    String rcv = access(node.receiver);
-    String args = formatArguments(node.selector.callStructure, node.arguments,
+    String rcv = access(node.receiverRef);
+    String args = formatArguments(node.selector.callStructure, node.argumentRefs,
         node.callingConvention);
     return '(InvokeMethod $rcv $name $args)';
   }
 
   String visitInvokeMethodDirectly(InvokeMethodDirectly node) {
-    String receiver = access(node.receiver);
+    String receiver = access(node.receiverRef);
     String name = node.selector.name;
-    String args = formatArguments(node.selector.callStructure, node.arguments,
+    String args = formatArguments(node.selector.callStructure, node.argumentRefs,
         node.callingConvention);
     return '(InvokeMethodDirectly $receiver $name $args)';
   }
@@ -231,22 +231,22 @@
     if (!node.target.name.isEmpty) {
       name = '${name}.${node.target.name}';
     }
-    String args = formatArguments(node.selector.callStructure, node.arguments);
+    String args = formatArguments(node.selector.callStructure, node.argumentRefs);
     return '(InvokeConstructor $name $args)';
   }
 
   String visitInvokeContinuation(InvokeContinuation node) {
-    String name = access(node.continuation);
+    String name = access(node.continuationRef);
     if (node.isRecursive) name = 'rec $name';
-    String args = node.arguments == null
+    String args = node.argumentRefs == null
         ? '**** NULL ****'
-	: node.arguments.map(access).join(' ');
+	: node.argumentRefs.map(access).join(' ');
     String escaping = node.isEscapingTry ? ' escape' : '';
     return '$indentation(InvokeContinuation $name ($args)$escaping)';
   }
 
   String visitThrow(Throw node) {
-    String value = access(node.value);
+    String value = access(node.valueRef);
     return '$indentation(Throw $value)';
   }
 
@@ -255,13 +255,13 @@
   }
 
   String visitBranch(Branch node) {
-    String condition = access(node.condition);
-    assert(isBranchTarget(node.trueContinuation.definition));
-    assert(isBranchTarget(node.falseContinuation.definition));
+    String condition = access(node.conditionRef);
+    assert(isBranchTarget(node.trueContinuation));
+    assert(isBranchTarget(node.falseContinuation));
     String trueCont =
-        indentBlock(() => visit(node.trueContinuation.definition));
+        indentBlock(() => visit(node.trueContinuation));
     String falseCont =
-        indentBlock(() => visit(node.falseContinuation.definition));
+        indentBlock(() => visit(node.falseContinuation));
     String strict = node.isStrictCheck ? 'Strict' : 'NonStrict';
     return '$indentation(Branch $strict $condition\n$trueCont\n$falseCont)';
   }
@@ -295,45 +295,45 @@
   }
 
   String visitGetMutable(GetMutable node) {
-    return '(GetMutable ${access(node.variable)})';
+    return '(GetMutable ${access(node.variableRef)})';
   }
 
   String visitSetMutable(SetMutable node) {
-    String value = access(node.value);
-    return '(SetMutable ${access(node.variable)} $value)';
+    String value = access(node.valueRef);
+    return '(SetMutable ${access(node.variableRef)} $value)';
   }
 
   String visitTypeCast(TypeCast node) {
-    String value = access(node.value);
-    String typeArguments = node.typeArguments.map(access).join(' ');
+    String value = access(node.valueRef);
+    String typeArguments = node.typeArgumentRefs.map(access).join(' ');
     return '(TypeCast $value ${node.dartType} ($typeArguments))';
   }
 
   String visitTypeTest(TypeTest node) {
-    String value = access(node.value);
-    String typeArguments = node.typeArguments.map(access).join(' ');
+    String value = access(node.valueRef);
+    String typeArguments = node.typeArgumentRefs.map(access).join(' ');
     return '(TypeTest $value ${node.dartType} ($typeArguments))';
   }
 
   String visitTypeTestViaFlag(TypeTestViaFlag node) {
-    String interceptor = access(node.interceptor);
+    String interceptor = access(node.interceptorRef);
     return '(TypeTestViaFlag $interceptor ${node.dartType})';
   }
 
   String visitLiteralList(LiteralList node) {
-    String values = node.values.map(access).join(' ');
+    String values = node.valueRefs.map(access).join(' ');
     return '(LiteralList ($values))';
   }
 
   String visitSetField(SetField node) {
-    String object = access(node.object);
+    String object = access(node.objectRef);
     String field = node.field.name;
-    String value = access(node.value);
+    String value = access(node.valueRef);
     return '(SetField $object $field $value)';
   }
 
   String visitGetField(GetField node) {
-    String object = access(node.object);
+    String object = access(node.objectRef);
     String field = node.field.name;
     return '(GetField $object $field)';
   }
@@ -345,7 +345,7 @@
 
   String visitSetStatic(SetStatic node) {
     String element = node.element.name;
-    String value = access(node.value);
+    String value = access(node.valueRef);
     return '(SetStatic $element $value)';
   }
 
@@ -360,79 +360,79 @@
 
   String visitCreateInstance(CreateInstance node) {
     String className = node.classElement.name;
-    String arguments = node.arguments.map(access).join(' ');
-    String typeInformation = optionalAccess(node.typeInformation);
+    String arguments = node.argumentRefs.map(access).join(' ');
+    String typeInformation = optionalAccess(node.typeInformationRef);
     return '(CreateInstance $className ($arguments) ($typeInformation))';
   }
 
   String visitInterceptor(Interceptor node) {
-    return '(Interceptor ${access(node.input)})';
+    return '(Interceptor ${access(node.inputRef)})';
   }
 
   String visitReifyRuntimeType(ReifyRuntimeType node) {
-    return '(ReifyRuntimeType ${access(node.value)})';
+    return '(ReifyRuntimeType ${access(node.valueRef)})';
   }
 
   String visitReadTypeVariable(ReadTypeVariable node) {
-    return '(ReadTypeVariable ${access(node.target)}.${node.variable})';
+    return '(ReadTypeVariable ${access(node.targetRef)}.${node.variable})';
   }
 
   String visitTypeExpression(TypeExpression node) {
-    String args = node.arguments.map(access).join(' ');
+    String args = node.argumentRefs.map(access).join(' ');
     return '(TypeExpression ${node.kindAsString} ${node.dartType} ($args))';
   }
 
   String visitCreateInvocationMirror(CreateInvocationMirror node) {
     String selector = node.selector.name;
-    String args = node.arguments.map(access).join(' ');
+    String args = node.argumentRefs.map(access).join(' ');
     return '(CreateInvocationMirror $selector ($args))';
   }
 
   String visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
     String operator = node.operator.toString();
-    String args = node.arguments.map(access).join(' ');
+    String args = node.argumentRefs.map(access).join(' ');
     return '(ApplyBuiltinOperator $operator ($args))';
   }
 
   String visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
     String method = node.method.toString();
-    String receiver = access(node.receiver);
-    String args = node.arguments.map(access).join(' ');
+    String receiver = access(node.receiverRef);
+    String args = node.argumentRefs.map(access).join(' ');
     return '(ApplyBuiltinMethod $method $receiver ($args))';
   }
 
   String visitForeignCode(ForeignCode node) {
-    String arguments = node.arguments.map(access).join(' ');
+    String arguments = node.argumentRefs.map(access).join(' ');
     return '(JS "${node.codeTemplate.source}" ($arguments))';
   }
 
   String visitGetLength(GetLength node) {
-    String object = access(node.object);
+    String object = access(node.objectRef);
     return '(GetLength $object)';
   }
 
   String visitGetIndex(GetIndex node) {
-    String object = access(node.object);
-    String index = access(node.index);
+    String object = access(node.objectRef);
+    String index = access(node.indexRef);
     return '(GetIndex $object $index)';
   }
 
   String visitSetIndex(SetIndex node) {
-    String object = access(node.object);
-    String index = access(node.index);
-    String value = access(node.value);
+    String object = access(node.objectRef);
+    String index = access(node.indexRef);
+    String value = access(node.valueRef);
     return '(SetIndex $object $index $value)';
   }
 
   @override
   String visitAwait(Await node) {
-    String value = access(node.input);
+    String value = access(node.inputRef);
     return '(Await $value)';
   }
 
   @override
   String visitYield(Yield node) {
-    String value = access(node.input);
+    String value = access(node.inputRef);
     return '(Yield $value)';
   }
 
@@ -442,15 +442,15 @@
   }
 
   String visitBoundsCheck(BoundsCheck node) {
-    String object = access(node.object);
-    String index = optionalAccess(node.index);
-    String length = optionalAccess(node.length);
+    String object = access(node.objectRef);
+    String index = optionalAccess(node.indexRef);
+    String length = optionalAccess(node.lengthRef);
     return '(BoundsCheck $object $index $length ${node.checkString})';
   }
 
   String visitReceiverCheck(ReceiverCheck node) {
-    String value = access(node.value);
-    String condition = optionalAccess(node.condition);
+    String value = access(node.valueRef);
+    String condition = optionalAccess(node.conditionRef);
     return '(ReceiverCheck $value ${node.selector} $condition '
         '${node.flagString}))';
   }
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
index dd69e3e..1c7779b 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
@@ -137,27 +137,27 @@
 
   visitLetMutable(cps_ir.LetMutable node) {
     String id = names.name(node.variable);
-    printStmt(id, "LetMutable $id = ${formatReference(node.value)}");
+    printStmt(id, "LetMutable $id = ${formatReference(node.valueRef)}");
     visit(node.body);
   }
 
   visitInvokeStatic(cps_ir.InvokeStatic node) {
     String callName = node.selector.name;
-    String args = node.arguments.map(formatReference).join(', ');
+    String args = node.argumentRefs.map(formatReference).join(', ');
     return "InvokeStatic $callName ($args)";
   }
 
   visitInvokeMethod(cps_ir.InvokeMethod node) {
-    String receiver = formatReference(node.receiver);
+    String receiver = formatReference(node.receiverRef);
     String callName = node.selector.name;
-    String args = node.arguments.map(formatReference).join(', ');
+    String args = node.argumentRefs.map(formatReference).join(', ');
     return "InvokeMethod $receiver $callName ($args)";
   }
 
   visitInvokeMethodDirectly(cps_ir.InvokeMethodDirectly node) {
-    String receiver = formatReference(node.receiver);
+    String receiver = formatReference(node.receiverRef);
     String callName = node.selector.name;
-    String args = node.arguments.map(formatReference).join(', ');
+    String args = node.argumentRefs.map(formatReference).join(', ');
     return "InvokeMethodDirectly $receiver $callName ($args)";
   }
 
@@ -169,13 +169,13 @@
     } else {
       callName = '${className}.${node.target.name}';
     }
-    String args = node.arguments.map(formatReference).join(', ');
+    String args = node.argumentRefs.map(formatReference).join(', ');
     return "InvokeConstructor $callName ($args)";
   }
 
   visitThrow(cps_ir.Throw node) {
     String dummy = names.name(node);
-    String value = formatReference(node.value);
+    String value = formatReference(node.valueRef);
     printStmt(dummy, "Throw $value");
   }
 
@@ -190,46 +190,46 @@
   }
 
   visitLiteralList(cps_ir.LiteralList node) {
-    String values = node.values.map(formatReference).join(', ');
+    String values = node.valueRefs.map(formatReference).join(', ');
     return "LiteralList ($values)";
   }
 
   visitTypeCast(cps_ir.TypeCast node) {
-    String value = formatReference(node.value);
-    String args = node.typeArguments.map(formatReference).join(', ');
+    String value = formatReference(node.valueRef);
+    String args = node.typeArgumentRefs.map(formatReference).join(', ');
     return "TypeCast ($value ${node.dartType} ($args))";
   }
 
   visitInvokeContinuation(cps_ir.InvokeContinuation node) {
     String dummy = names.name(node);
-    String kont = formatReference(node.continuation);
-    String args = node.arguments.map(formatReference).join(', ');
+    String kont = formatReference(node.continuationRef);
+    String args = node.argumentRefs.map(formatReference).join(', ');
     printStmt(dummy, "InvokeContinuation $kont ($args)");
   }
 
   visitBranch(cps_ir.Branch node) {
     String dummy = names.name(node);
-    String condition = formatReference(node.condition);
-    String trueCont = formatReference(node.trueContinuation);
-    String falseCont = formatReference(node.falseContinuation);
+    String condition = formatReference(node.conditionRef);
+    String trueCont = formatReference(node.trueContinuationRef);
+    String falseCont = formatReference(node.falseContinuationRef);
     String strict = node.isStrictCheck ? "Strict" : "NonStrict";
     printStmt(dummy, "Branch $condition ($trueCont, $falseCont) $strict");
   }
 
   visitAwait(cps_ir.Await node) {
-    String value = formatReference(node.input);
+    String value = formatReference(node.inputRef);
     return 'Await $value';
   }
 
   visitYield(cps_ir.Yield node) {
     String name = node.hasStar ? 'YieldStar' : 'Yield';
-    String value = formatReference(node.input);
+    String value = formatReference(node.inputRef);
     return '$name $value';
   }
 
   visitSetMutable(cps_ir.SetMutable node) {
-    String variable = names.name(node.variable.definition);
-    String value = formatReference(node.value);
+    String variable = names.name(node.variable);
+    String value = formatReference(node.valueRef);
     return 'SetMutable $variable := $value';
   }
 
@@ -260,32 +260,35 @@
   }
 
   visitSetField(cps_ir.SetField node) {
-    String object = formatReference(node.object);
+    String object = formatReference(node.objectRef);
     String field = node.field.name;
-    String value = formatReference(node.value);
+    String value = formatReference(node.valueRef);
     return 'SetField $object.$field = $value';
   }
 
   visitGetField(cps_ir.GetField node) {
-    String object = formatReference(node.object);
+    String object = formatReference(node.objectRef);
     String field = node.field.name;
-    return 'GetField($object.$field)';
+    String finalFlag = node.isFinal ? 'final' : 'non-final';
+    return 'GetField $object.$field $finalFlag';
   }
 
   visitGetStatic(cps_ir.GetStatic node) {
     String element = node.element.name;
-    return 'GetStatic($element)';
+    String finalFlag = node.isFinal ? 'final' : 'non-final';
+    return 'GetStatic $element $finalFlag';
   }
 
   visitSetStatic(cps_ir.SetStatic node) {
     String element = node.element.name;
-    String value = formatReference(node.value);
+    String value = formatReference(node.valueRef);
     return 'SetStatic $element = $value';
   }
 
   visitGetLazyStatic(cps_ir.GetLazyStatic node) {
     String element = node.element.name;
-    return "GetLazyStatic $element";
+    String finalFlag = node.isFinal ? 'final' : 'non-final';
+    return "GetLazyStatic $element $finalFlag";
   }
 
   visitCreateBox(cps_ir.CreateBox node) {
@@ -294,86 +297,87 @@
 
   visitCreateInstance(cps_ir.CreateInstance node) {
     String className = node.classElement.name;
-    String arguments = node.arguments.map(formatReference).join(', ');
-    String typeInformation = formatReference(node.typeInformation);
+    String arguments = node.argumentRefs.map(formatReference).join(', ');
+    String typeInformation = formatReference(node.typeInformationRef);
     return 'CreateInstance $className ($arguments) <$typeInformation>';
   }
 
   visitInterceptor(cps_ir.Interceptor node) {
-    return 'Interceptor(${formatReference(node.input)}, '
+    return 'Interceptor(${formatReference(node.inputRef)}, '
            '${node.interceptedClasses})';
   }
 
   visitGetMutable(cps_ir.GetMutable node) {
-    String variable = names.name(node.variable.definition);
+    String variable = names.name(node.variable);
     return 'GetMutable $variable';
   }
 
   visitReadTypeVariable(cps_ir.ReadTypeVariable node) {
     return "ReadTypeVariable ${node.variable.element} "
-        "${formatReference(node.target)}";
+        "${formatReference(node.targetRef)}";
   }
 
   visitReifyRuntimeType(cps_ir.ReifyRuntimeType node) {
-    return "ReifyRuntimeType ${formatReference(node.value)}";
+    return "ReifyRuntimeType ${formatReference(node.valueRef)}";
   }
 
   visitTypeExpression(cps_ir.TypeExpression node) {
     return "TypeExpression ${node.kindAsString} ${node.dartType}"
-        "${node.arguments.map(formatReference).join(', ')}";
+        "${node.argumentRefs.map(formatReference).join(', ')}";
   }
 
   visitCreateInvocationMirror(cps_ir.CreateInvocationMirror node) {
-    String args = node.arguments.map(formatReference).join(', ');
+    String args = node.argumentRefs.map(formatReference).join(', ');
     return "CreateInvocationMirror(${node.selector.name}, $args)";
   }
 
   visitTypeTest(cps_ir.TypeTest node) {
-    String value = formatReference(node.value);
-    String args = node.typeArguments.map(formatReference).join(', ');
+    String value = formatReference(node.valueRef);
+    String args = node.typeArgumentRefs.map(formatReference).join(', ');
     return "TypeTest ($value ${node.dartType} ($args))";
   }
 
   visitTypeTestViaFlag(cps_ir.TypeTestViaFlag node) {
-    String interceptor = formatReference(node.interceptor);
+    String interceptor = formatReference(node.interceptorRef);
     return "TypeTestViaFlag ($interceptor ${node.dartType})";
   }
 
   visitApplyBuiltinOperator(cps_ir.ApplyBuiltinOperator node) {
     String operator = node.operator.toString();
-    String args = node.arguments.map(formatReference).join(', ');
+    String args = node.argumentRefs.map(formatReference).join(', ');
     return 'ApplyBuiltinOperator $operator ($args)';
   }
 
   visitApplyBuiltinMethod(cps_ir.ApplyBuiltinMethod node) {
     String method = node.method.toString();
-    String receiver = formatReference(node.receiver);
-    String args = node.arguments.map(formatReference).join(', ');
+    String receiver = formatReference(node.receiverRef);
+    String args = node.argumentRefs.map(formatReference).join(', ');
     return 'ApplyBuiltinMethod $method $receiver ($args)';
   }
 
   visitForeignCode(cps_ir.ForeignCode node) {
     String id = names.name(node);
-    String arguments = node.arguments.map(formatReference).join(', ');
+    String arguments = node.argumentRefs.map(formatReference).join(', ');
     printStmt(id,
         "ForeignCode ${node.type} ${node.codeTemplate.source} $arguments");
   }
 
   visitGetLength(cps_ir.GetLength node) {
-    String object = formatReference(node.object);
-    return 'GetLength $object';
+    String object = formatReference(node.objectRef);
+    String finalFlag = node.isFinal ? 'final' : 'non-final';
+    return 'GetLength $object $finalFlag';
   }
 
   visitGetIndex(cps_ir.GetIndex node) {
-    String object = formatReference(node.object);
-    String index = formatReference(node.index);
+    String object = formatReference(node.objectRef);
+    String index = formatReference(node.indexRef);
     return 'GetIndex $object $index';
   }
 
   visitSetIndex(cps_ir.SetIndex node) {
-    String object = formatReference(node.object);
-    String index = formatReference(node.index);
-    String value = formatReference(node.value);
+    String object = formatReference(node.objectRef);
+    String index = formatReference(node.indexRef);
+    String value = formatReference(node.valueRef);
     return 'SetIndex $object $index $value';
   }
 
@@ -383,19 +387,19 @@
   }
 
   visitBoundsCheck(cps_ir.BoundsCheck node) {
-    String object = formatReference(node.object);
-    String index = node.index == null
+    String object = formatReference(node.objectRef);
+    String index = node.indexRef == null
         ? 'no-index'
-        : formatReference(node.index);
-    String length = node.length == null
+        : formatReference(node.indexRef);
+    String length = node.lengthRef == null
         ? 'no-length'
-        : formatReference(node.length);
+        : formatReference(node.lengthRef);
     return 'BoundsCheck $object $index $length ${node.checkString}';
   }
 
   visitReceiverCheck(cps_ir.ReceiverCheck node) {
-    String value = formatReference(node.value);
-    String condition = formatReference(node.condition);
+    String value = formatReference(node.valueRef);
+    String condition = formatReference(node.conditionRef);
     return 'ReceiverCheck $value $condition ${node.selector} '
         '${node.flagString}';
   }
@@ -506,7 +510,7 @@
   }
 
   visitInvokeContinuation(cps_ir.InvokeContinuation exp) {
-    addEdgeToContinuation(exp.continuation);
+    addEdgeToContinuation(exp.continuationRef);
   }
 
   visitInvokeStatic(cps_ir.InvokeStatic node) {
@@ -539,11 +543,11 @@
   }
 
   visitBranch(cps_ir.Branch exp) {
-    cps_ir.Continuation trueTarget = exp.trueContinuation.definition;
+    cps_ir.Continuation trueTarget = exp.trueContinuation;
     if (!trueTarget.isReturnContinuation) {
       currentBlock.addEdgeTo(getBlock(trueTarget));
     }
-    cps_ir.Continuation falseTarget = exp.falseContinuation.definition;
+    cps_ir.Continuation falseTarget = exp.falseContinuation;
     if (!falseTarget.isReturnContinuation) {
       currentBlock.addEdgeTo(getBlock(falseTarget));
     }
diff --git a/pkg/compiler/lib/src/cps_ir/eagerly_load_statics.dart b/pkg/compiler/lib/src/cps_ir/eagerly_load_statics.dart
index 6f733e3..e03f9ca 100644
--- a/pkg/compiler/lib/src/cps_ir/eagerly_load_statics.dart
+++ b/pkg/compiler/lib/src/cps_ir/eagerly_load_statics.dart
@@ -7,6 +7,7 @@
 import 'cps_ir_nodes.dart';
 import 'optimizers.dart' show Pass;
 import '../elements/elements.dart';
+import 'cps_fragment.dart';
 
 /// Replaces [GetLazyStatic] with [GetStatic] when the static field is known
 /// to have been initialized.
@@ -30,6 +31,12 @@
     visit(node.body);
   }
 
+  Expression traverseLetPrim(LetPrim node) {
+    Expression next = node.body;
+    visit(node.primitive);
+    return next;
+  }
+
   Expression traverseLetCont(LetCont node) {
     for (Continuation cont in node.continuations) {
       initializersAt[cont] = cloneFieldMap(initializerFor);
@@ -51,10 +58,13 @@
 
   void visitGetLazyStatic(GetLazyStatic node) {
     Primitive initializer = initializerFor[node.element];
-    if (initializer != null) {
-      GetStatic newNode = new GetStatic.witnessed(node.element, initializer,
-          node.sourceInformation);
-      newNode.type = node.type;
+    if (initializer is GetLazyStatic && initializer.isFinal) {
+      // No reason to create a GetStatic when the field is final.
+      node.replaceWithFragment(new CpsFragment(), initializer);
+    } else if (initializer != null) {
+      GetStatic newNode = new GetStatic.witnessed(node.element,
+          initializer, sourceInformation: node.sourceInformation)
+          ..type = node.type;
       node.replaceWith(newNode);
     } else {
       initializerFor[node.element] = node;
diff --git a/pkg/compiler/lib/src/cps_ir/effects.dart b/pkg/compiler/lib/src/cps_ir/effects.dart
new file mode 100644
index 0000000..9ab55cd
--- /dev/null
+++ b/pkg/compiler/lib/src/cps_ir/effects.dart
@@ -0,0 +1,197 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+library dart2js.cps_ir.effects;
+
+import 'dart:typed_data';
+import '../universe/side_effects.dart' show SideEffects;
+
+/// Bitmasks for tracking non-local side effects and dependencies.
+///
+/// All effects must be attributed to an effect area.  The `other` area is a
+/// catch-all for any effect that does not belong to any of the specific areas;
+/// this includes external effects such as printing to the console.
+class Effects {
+  // Effect areas.
+  // These are bit positions, not bit masks. They are private because it is
+  // otherwise easy to mistake them for bitmasks.
+  static const int _staticField = 0;
+  static const int _instanceField = 1;
+  static const int _indexableContent = 2;
+  static const int _indexableLength = 3;
+  static const int _other = 4;
+  static const int numberOfEffectAreas = 5;
+
+  // Bitmasks for computation that modifies state in a given area.
+  static const int _changes = 1;
+  static const int changesStaticField = _changes << _staticField;
+  static const int changesInstanceField = _changes << _instanceField;
+  static const int changesIndexableContent = _changes << _indexableContent;
+  static const int changesIndexableLength = _changes << _indexableLength;
+  static const int changesOther = _changes << _other;
+
+  static const int changesAll =
+      changesStaticField |
+      changesInstanceField |
+      changesIndexableContent |
+      changesIndexableLength |
+      changesOther;
+
+  // Bitmasks for computation that depends on state in a given area.
+  static const int _depends = 1 << numberOfEffectAreas;
+  static const int dependsOnStaticField = _depends << _staticField;
+  static const int dependsOnInstanceField = _depends << _instanceField;
+  static const int dependsOnIndexableContent = _depends << _indexableContent;
+  static const int dependsOnIndexableLength = _depends << _indexableLength;
+  static const int dependsOnOther = _depends << _other;
+
+  static const int dependsOnAll =
+      dependsOnStaticField |
+      dependsOnInstanceField |
+      dependsOnIndexableContent |
+      dependsOnIndexableLength |
+      dependsOnOther;
+
+  static const int all = changesAll | dependsOnAll;
+  static const int none = 0;
+
+  static int _changesArea(int effectArea) => _changes << effectArea;
+
+  static int _dependsOnArea(int effectArea) => _depends << effectArea;
+
+  static int changesToDepends(int changesFlags) {
+    return (changesFlags & changesAll) << numberOfEffectAreas;
+  }
+
+  static int dependsToChanges(int dependsFlags) {
+    return (dependsFlags & dependsOnAll) >> numberOfEffectAreas;
+  }
+
+  /// Converts [SideEffects] from a JS annotation or type inference to the
+  /// more fine-grained flag set.
+  //
+  // TODO(asgerf): Once we finalize the set of flags to use, unify the two
+  //               systems.
+  static int from(SideEffects fx) {
+    int result = 0;
+    if (fx.changesInstanceProperty()) {
+      result |= changesInstanceField;
+    }
+    if (fx.changesStaticProperty()) {
+      result |= changesStaticField;
+    }
+    if (fx.changesIndex()) {
+      result |= changesIndexableContent | changesIndexableLength;
+    }
+    if (fx.hasSideEffects()) {
+      result |= changesOther;
+    }
+    if (fx.dependsOnInstancePropertyStore()) {
+      result |= dependsOnInstanceField;
+    }
+    if (fx.dependsOnStaticPropertyStore()) {
+      result |= dependsOnStaticField;
+    }
+    if (fx.dependsOnIndexStore()) {
+      result |= dependsOnIndexableContent | dependsOnIndexableLength;
+    }
+    if (fx.dependsOnSomething()) {
+      result |= dependsOnOther;
+    }
+    return result;
+  }
+}
+
+/// Creates fresh IDs to ensure effect numbers do not clash with each other.
+class EffectNumberer {
+  int _id = 0;
+  int next() => ++_id;
+
+  /// Special effect number that can be used in place for an effect area that
+  /// is irrelevant for a computation.
+  ///
+  /// This value is never returned by [next].
+  static const int none = 0;
+}
+
+/// A mutable vector of effect numbers, one for each effect area.
+///
+/// Effect numbers are used to identify regions of code wherein the given
+/// effect area is unmodified.
+class EffectNumbers {
+  final Int32List _effectNumbers = new Int32List(Effects.numberOfEffectAreas);
+
+  EffectNumbers._zero();
+
+  EffectNumbers.fresh(EffectNumberer numberer) {
+    reset(numberer);
+  }
+
+  EffectNumbers copy() {
+    return new EffectNumbers._zero().._effectNumbers.setAll(0, _effectNumbers);
+  }
+
+  int operator[](int i) => _effectNumbers[i];
+
+  void operator[]=(int i, int value) {
+    _effectNumbers[i] = value;
+  }
+
+  int get staticField => _effectNumbers[Effects._staticField];
+  int get instanceField => _effectNumbers[Effects._instanceField];
+  int get indexableContent => _effectNumbers[Effects._indexableContent];
+  int get indexableLength => _effectNumbers[Effects._indexableLength];
+  int get other => _effectNumbers[Effects._other];
+
+  void set staticField(int n) {
+    _effectNumbers[Effects._staticField] = n;
+  }
+  void set instanceField(int n) {
+    _effectNumbers[Effects._instanceField] = n;
+  }
+  void set indexableContent(int n) {
+    _effectNumbers[Effects._indexableContent] = n;
+  }
+  void set indexableLength(int n) {
+    _effectNumbers[Effects._indexableLength] = n;
+  }
+  void set other(int n) {
+    _effectNumbers[Effects._other] = n;
+  }
+
+  void reset(EffectNumberer numberer) {
+    for (int i = 0; i < Effects.numberOfEffectAreas; ++i) {
+      _effectNumbers[i] = numberer.next();
+    }
+  }
+
+  void join(EffectNumberer numberer, EffectNumbers other) {
+    for (int i = 0; i < Effects.numberOfEffectAreas; ++i) {
+      if (_effectNumbers[i] != other._effectNumbers[i]) {
+        _effectNumbers[i] = numberer.next();
+      }
+    }
+  }
+
+  void change(EffectNumberer numberer, int changeFlags) {
+    for (int i = 0; i < Effects.numberOfEffectAreas; ++i) {
+      if (changeFlags & Effects._changesArea(i) != 0) {
+        _effectNumbers[i] = numberer.next();
+      }
+    }
+  }
+
+  /// Builds a vector where all entries that are not depended on are replaced
+  /// by [EffectNumberer.none].
+  //
+  // TODO(asgerf): Use this in GVN to simplify the dispatching code.
+  List<int> getDependencies(int dependsFlags) {
+    Int32List copy = new Int32List.fromList(_effectNumbers);
+    for (int i = 0; i < Effects.numberOfEffectAreas; ++i) {
+      if (dependsFlags & Effects._dependsOnArea(i) == 0) {
+        copy[i] = EffectNumberer.none;
+      }
+    }
+    return copy;
+  }
+}
diff --git a/pkg/compiler/lib/src/cps_ir/finalize.dart b/pkg/compiler/lib/src/cps_ir/finalize.dart
index dad9e51..9376800 100644
--- a/pkg/compiler/lib/src/cps_ir/finalize.dart
+++ b/pkg/compiler/lib/src/cps_ir/finalize.dart
@@ -38,11 +38,11 @@
   CpsFragment visitBoundsCheck(BoundsCheck node) {
     CpsFragment cps = new CpsFragment(node.sourceInformation);
     if (node.hasNoChecks) {
-      node..replaceUsesWith(node.object.definition)..destroy();
+      node..replaceUsesWith(node.object)..destroy();
       return cps;
     }
     Continuation fail = cps.letCont();
-    Primitive index = node.index.definition;
+    Primitive index = node.index;
     if (node.hasIntegerCheck) {
       cps.ifTruthy(cps.applyBuiltin(BuiltinOperator.IsNotUnsigned32BitInteger,
           [index, index]))
@@ -53,7 +53,7 @@
           .invokeContinuation(fail);
     }
     if (node.hasUpperBoundCheck) {
-      Primitive length = node.length.definition;
+      Primitive length = node.length;
       if (length is GetLength &&
           length.hasExactlyOneUse &&
           areAdjacent(length, node)) {
@@ -69,19 +69,19 @@
     }
     if (node.hasEmptinessCheck) {
       cps.ifTruthy(cps.applyBuiltin(BuiltinOperator.StrictEq,
-          [node.length.definition, cps.makeZero()]))
+          [node.length, cps.makeZero()]))
           .invokeContinuation(fail);
     }
     cps.insideContinuation(fail).invokeStaticThrower(
           helpers.throwIndexOutOfRangeException,
-          [node.object.definition, index]);
-    node..replaceUsesWith(node.object.definition)..destroy();
+          [node.object, index]);
+    node..replaceUsesWith(node.object)..destroy();
     return cps;
   }
 
   void visitGetStatic(GetStatic node) {
-    if (node.witness != null) {
-      node..witness.unlink()..witness = null;
+    if (node.witnessRef != null) {
+      node..witnessRef.unlink()..witnessRef = null;
     }
   }
 
@@ -92,9 +92,8 @@
       // type of an object is immutable, but the type of an array can change
       // after allocation.  After the finalize pass, this assumption is no
       // longer needed, so we can replace the remaining idenitity templates.
-      Refinement refinement = new Refinement(
-          node.arguments.single.definition,
-          node.type)..type = node.type;
+      Refinement refinement = new Refinement(node.argument(0), node.type)
+          ..type = node.type;
       node.replaceWith(refinement);
     }
   }
diff --git a/pkg/compiler/lib/src/cps_ir/gvn.dart b/pkg/compiler/lib/src/cps_ir/gvn.dart
index 46f5d93..8bf896d 100644
--- a/pkg/compiler/lib/src/cps_ir/gvn.dart
+++ b/pkg/compiler/lib/src/cps_ir/gvn.dart
@@ -15,6 +15,7 @@
 import '../js_backend/js_backend.dart' show JavaScriptBackend;
 import '../constants/values.dart';
 import 'type_mask_system.dart';
+import 'effects.dart';
 
 /// Eliminates redundant primitives by reusing the value of another primitive
 /// that is known to have the same result.  Primitives are also hoisted out of
@@ -36,11 +37,6 @@
 //    - Since the new type may be worse, insert a refinement at the old
 //      definition site, so we do not degrade existing type information.
 //
-//  TODO(asgerf): Put this pass at a better place in the pipeline.  We currently
-//    cannot put it anywhere we want, because this pass relies on refinement
-//    nodes being present (for safety), whereas other passes rely on refinement
-//    nodes being absent (for simplicity & precision).
-//
 class GVN extends TrampolineRecursiveVisitor implements Pass {
   String get passName => 'GVN';
 
@@ -54,11 +50,13 @@
   LoopHierarchy loopHierarchy;
   LoopSideEffects loopEffects;
 
+  final EffectNumberer effectNumberer = new EffectNumberer();
+
   /// Effect numbers at the given join point.
   Map<Continuation, EffectNumbers> effectsAt = <Continuation, EffectNumbers>{};
 
   /// The effect numbers at the current position (during traversal).
-  EffectNumbers effectNumbers = new EffectNumbers();
+  EffectNumbers effectNumbers;
 
   /// The loop currently enclosing the binding of a given primitive.
   final Map<Primitive, Continuation> loopHeaderFor =
@@ -80,10 +78,8 @@
 
   GVN(this.compiler, this.types);
 
-  int _usedEffectNumbers = 0;
-  int makeNewEffect() => ++_usedEffectNumbers;
-
   void rewrite(FunctionDefinition node) {
+    effectNumbers = new EffectNumbers.fresh(effectNumberer);
     gvnVectorBuilder = new GvnVectorBuilder(gvnFor, compiler, types);
     loopHierarchy = new LoopHierarchy(node);
     loopEffects =
@@ -125,7 +121,7 @@
     // GetLazyStatic is GVN'ed like a GetStatic, but the effects of the static
     // initializer occur before reading the field.
     if (prim is GetLazyStatic) {
-      visit(prim);
+      addSideEffectsOfPrimitive(prim);
     }
 
     // Compute the GVN vector for this computation.
@@ -135,7 +131,7 @@
     // Do this after computing the GVN vector so the primitive's GVN is not
     // influenced by its own side effects, except in the case of GetLazyStatic.
     if (prim is! GetLazyStatic) {
-      visit(prim);
+      addSideEffectsOfPrimitive(prim);
     }
 
     if (vector == null) {
@@ -347,18 +343,6 @@
     return prim is Constant && (prim.value.isPrimitive || prim.value.isDummy);
   }
 
-  /// True if [element] is a final or constant field or a function.
-  bool isImmutable(Element element) {
-    if (element.isField && backend.isNative(element)) return false;
-    return element.isField && world.fieldNeverChanges(element) ||
-           element.isFunction;
-  }
-
-  bool isImmutableLength(GetLength length) {
-    return types.isDefinitelyFixedLengthIndexable(length.object.definition.type,
-        allowNull: true);
-  }
-
   /// Assuming [prim] has no side effects, returns true if it can safely
   /// be hoisted out of [loop] without changing its value or changing the timing
   /// of a thrown exception.
@@ -369,56 +353,26 @@
     if (!prim.isSafeForElimination && loop != currentLoopHeader) {
       return false;
     }
-    if (prim is GetLength && !isImmutableLength(prim)) {
-      return !loopEffects.loopChangesLength(loop);
-    } else if (prim is GetField && !isImmutable(prim.field)) {
-      return !loopEffects.getSideEffectsInLoop(loop).changesInstanceProperty();
-    } else if (prim is GetStatic && !isImmutable(prim.element)) {
-      return !loopEffects.getSideEffectsInLoop(loop).changesStaticProperty();
-    } else if (prim is GetIndex) {
-      return !loopEffects.getSideEffectsInLoop(loop).changesIndex();
-    } else {
-      return true;
-    }
+    int effects = loopEffects.getSideEffectsInLoop(loop);
+    return Effects.changesToDepends(effects) & prim.effects == 0;
   }
 
   // ------------------ TRAVERSAL AND EFFECT NUMBERING ---------------------
   //
   // These methods traverse the IR while updating the current effect numbers.
   // They are not specific to GVN.
-  //
-  // TODO(asgerf): Avoid duplicated code for side effect analysis.
-  // Should be easier to fix once primitives and call expressions are the same.
 
-  void addSideEffects(SideEffects fx, {bool length: true}) {
-    if (fx.changesInstanceProperty()) {
-      effectNumbers.instanceField = makeNewEffect();
-    }
-    if (fx.changesStaticProperty()) {
-      effectNumbers.staticField = makeNewEffect();
-    }
-    if (fx.changesIndex()) {
-      effectNumbers.indexableContent = makeNewEffect();
-    }
-    if (length && fx.changesIndex()) {
-      effectNumbers.indexableLength = makeNewEffect();
-    }
+  void addSideEffectsOfPrimitive(Primitive prim) {
+    addSideEffects(prim.effects);
   }
 
-  void addAllSideEffects() {
-    effectNumbers.instanceField = makeNewEffect();
-    effectNumbers.staticField = makeNewEffect();
-    effectNumbers.indexableContent = makeNewEffect();
-    effectNumbers.indexableLength = makeNewEffect();
+  void addSideEffects(int effectFlags) {
+    effectNumbers.change(effectNumberer, effectFlags);
   }
 
   Expression traverseLetHandler(LetHandler node) {
     // Assume any kind of side effects may occur in the try block.
-    effectsAt[node.handler] = new EffectNumbers()
-      ..instanceField = makeNewEffect()
-      ..staticField = makeNewEffect()
-      ..indexableContent = makeNewEffect()
-      ..indexableLength = makeNewEffect();
+    effectsAt[node.handler] = new EffectNumbers.fresh(effectNumberer);
     push(node.handler);
     return node.body;
   }
@@ -433,10 +387,7 @@
       loopHeaderFor[param] = currentLoopHeader;
     }
     if (cont.isRecursive) {
-      addSideEffects(loopEffects.getSideEffectsInLoop(cont), length: false);
-      if (loopEffects.loopChangesLength(cont)) {
-        effectNumbers.indexableLength = makeNewEffect();
-      }
+      addSideEffects(loopEffects.getSideEffectsInLoop(cont));
       pushAction(() {
         List<int> hoistedBindings = loopHoistedBindings[cont];
         if (hoistedBindings != null) {
@@ -444,124 +395,32 @@
         }
       });
     } else {
-      EffectNumbers join = effectsAt[cont];
-      if (join != null) {
-        effectNumbers = join;
-      } else {
-        // This is a call continuation seen immediately after its use.
-        // Reuse the current effect numbers.
-      }
+      effectNumbers = effectsAt[cont];
+      assert(effectNumbers != null);
     }
 
     return cont.body;
   }
 
   void visitInvokeContinuation(InvokeContinuation node) {
-    Continuation cont = node.continuation.definition;
+    Continuation cont = node.continuation;
     if (cont.isRecursive) return;
     EffectNumbers join = effectsAt[cont];
     if (join == null) {
       effectsAt[cont] = effectNumbers.copy();
     } else {
-      if (effectNumbers.instanceField != join.instanceField) {
-        join.instanceField = makeNewEffect();
-      }
-      if (effectNumbers.staticField != join.staticField) {
-        join.staticField = makeNewEffect();
-      }
-      if (effectNumbers.indexableContent != join.indexableContent) {
-        join.indexableContent = makeNewEffect();
-      }
-      if (effectNumbers.indexableLength != join.indexableLength) {
-        join.indexableLength = makeNewEffect();
-      }
+      join.join(effectNumberer, effectNumbers);
     }
   }
 
   void visitBranch(Branch node) {
-    Continuation trueCont = node.trueContinuation.definition;
-    Continuation falseCont = node.falseContinuation.definition;
+    Continuation trueCont = node.trueContinuation;
+    Continuation falseCont = node.falseContinuation;
     // Copy the effect number vector once, so the analysis of one branch does
     // not influence the other.
     effectsAt[trueCont] = effectNumbers;
     effectsAt[falseCont] = effectNumbers.copy();
   }
-
-  void visitInvokeMethod(InvokeMethod node) {
-    addSideEffects(world.getSideEffectsOfSelector(node.selector, node.mask));
-  }
-
-  void visitInvokeStatic(InvokeStatic node) {
-    addSideEffects(world.getSideEffectsOfElement(node.target));
-  }
-
-  void visitInvokeMethodDirectly(InvokeMethodDirectly node) {
-    FunctionElement target = node.target;
-    if (target is ConstructorBodyElement) {
-      ConstructorBodyElement body = target;
-      target = body.constructor;
-    }
-    addSideEffects(world.getSideEffectsOfElement(target));
-  }
-
-  void visitInvokeConstructor(InvokeConstructor node) {
-    addSideEffects(world.getSideEffectsOfElement(node.target));
-  }
-
-  void visitSetStatic(SetStatic node) {
-    effectNumbers.staticField = makeNewEffect();
-  }
-
-  void visitSetField(SetField node) {
-    effectNumbers.instanceField = makeNewEffect();
-  }
-
-  void visitSetIndex(SetIndex node) {
-    effectNumbers.indexableContent = makeNewEffect();
-  }
-
-  void visitForeignCode(ForeignCode node) {
-    addSideEffects(node.nativeBehavior.sideEffects);
-  }
-
-  void visitGetLazyStatic(GetLazyStatic node) {
-    // TODO(asgerf): How do we get the side effects of a lazy field initializer?
-    addAllSideEffects();
-  }
-
-  void visitAwait(Await node) {
-    addAllSideEffects();
-  }
-
-  void visitYield(Yield node) {
-    addAllSideEffects();
-  }
-
-  void visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
-    // Push and pop.
-    effectNumbers.indexableContent = makeNewEffect();
-    effectNumbers.indexableLength = makeNewEffect();
-  }
-}
-
-/// For each of the four categories of heap locations, the IR is divided into
-/// regions wherein the given heap locations are known not to be modified.
-///
-/// Each region is identified by its "effect number".  Effect numbers from
-/// different categories have no relationship to each other.
-class EffectNumbers {
-  int indexableLength = 0;
-  int indexableContent = 0;
-  int staticField = 0;
-  int instanceField = 0;
-
-  EffectNumbers copy() {
-    return new EffectNumbers()
-      ..indexableLength = indexableLength
-      ..indexableContent = indexableContent
-      ..staticField = staticField
-      ..instanceField = instanceField;
-  }
 }
 
 /// Maps vectors to numbers, such that two vectors with the same contents
@@ -659,7 +518,7 @@
   }
 
   processGetLength(GetLength node) {
-    if (isImmutableLength(node)) {
+    if (node.isFinal) {
       // Omit the effect number for fixed-length lists.  Note that if a the list
       // gets refined to a fixed-length type, we still won't be able to GVN a
       // GetLength across the refinement, because the first GetLength uses an
@@ -670,16 +529,6 @@
     }
   }
 
-  bool isImmutable(Element element) {
-    return element.isFunction ||
-           element.isField && world.fieldNeverChanges(element);
-  }
-
-  bool isImmutableLength(GetLength length) {
-    return types.isDefinitelyFixedLengthIndexable(length.object.definition.type,
-        allowNull: true);
-  }
-
   bool isNativeField(FieldElement field) {
     // TODO(asgerf): We should add a GetNativeField instruction.
     return backend.isNative(field);
@@ -688,7 +537,7 @@
   processGetField(GetField node) {
     if (isNativeField(node.field)) {
       vector = null; // Native field access cannot be GVN'ed.
-    } else if (isImmutable(node.field)) {
+    } else if (node.isFinal) {
       vector = [GvnCode.GET_FIELD, node.field];
     } else {
       vector = [GvnCode.GET_FIELD, node.field, effectNumbers.instanceField];
@@ -700,7 +549,7 @@
   }
 
   visitGetStatic(GetStatic node) {
-    if (isImmutable(node.element)) {
+    if (node.isFinal) {
       vector = [GvnCode.GET_STATIC, node.element];
     } else {
       vector = [GvnCode.GET_STATIC, node.element, effectNumbers.staticField];
@@ -709,7 +558,7 @@
   }
 
   processGetLazyStatic(GetLazyStatic node) {
-    if (isImmutable(node.element)) {
+    if (node.isFinal) {
       vector = [GvnCode.GET_STATIC, node.element];
     } else {
       vector = [GvnCode.GET_STATIC, node.element, effectNumbers.staticField];
diff --git a/pkg/compiler/lib/src/cps_ir/inline.dart b/pkg/compiler/lib/src/cps_ir/inline.dart
index d6096af..6c9f30c 100644
--- a/pkg/compiler/lib/src/cps_ir/inline.dart
+++ b/pkg/compiler/lib/src/cps_ir/inline.dart
@@ -237,9 +237,9 @@
   static int sizeOf(InvocationPrimitive invoke, FunctionDefinition function) {
     SizeVisitor visitor = new SizeVisitor();
     visitor.visit(function);
-    visitor.countArgument(invoke.receiver, function.thisParameter);
-    for (int i = 0; i < invoke.arguments.length; ++i) {
-      visitor.countArgument(invoke.arguments[i], function.parameters[i]);
+    visitor.countArgument(invoke.receiverRef, function.thisParameter);
+    for (int i = 0; i < invoke.argumentRefs.length; ++i) {
+      visitor.countArgument(invoke.argumentRefs[i], function.parameters[i]);
     }
     return visitor.size;
   }
@@ -336,13 +336,13 @@
   /// function that takes optional arguments not passed at the call site.
   FunctionDefinition buildAdapter(InvokeMethod node, FunctionElement target) {
     Parameter thisParameter = new Parameter(new ThisParameterLocal(target))
-        ..type = node.receiver.definition.type;
+        ..type = node.receiver.type;
     List<Parameter> parameters = new List<Parameter>.generate(
-        node.arguments.length,
+        node.argumentRefs.length,
         (int index) {
           // TODO(kmillikin): Use a hint for the parameter names.
           return new Parameter(null)
-              ..type = node.arguments[index].definition.type;
+              ..type = node.argument(index).type;
         });
     Continuation returnContinuation = new Continuation.retrn();
     CpsFragment cps = new CpsFragment();
@@ -444,7 +444,7 @@
       return null;
     }
 
-    Reference<Primitive> dartReceiver = invoke.dartReceiverReference;
+    Reference<Primitive> dartReceiver = invoke.dartReceiverRef;
     TypeMask abstractReceiver =
         dartReceiver == null ? null : abstractType(dartReceiver);
     // The receiver is non-null in a method body, unless the receiver is known
@@ -455,7 +455,7 @@
             ? abstractReceiver
             : abstractReceiver.nonNullable();
     List<TypeMask> abstractArguments =
-        invoke.arguments.map(abstractType).toList();
+        invoke.argumentRefs.map(abstractType).toList();
     var cachedResult = _inliner.cache.get(target, callStructure,
         abstractReceiverInMethod,
         abstractArguments);
@@ -465,9 +465,8 @@
 
     Primitive finish(FunctionDefinition function) {
       _fragment = new CpsFragment(invoke.sourceInformation);
-      Primitive receiver = invoke.receiver?.definition;
-      List<Primitive> arguments =
-          invoke.arguments.map((Reference ref) => ref.definition).toList();
+      Primitive receiver = invoke.receiver;
+      List<Primitive> arguments = invoke.arguments.toList();
       // Add a null check to the inlined function body if necessary.  The
       // cached function body does not contain the null check.
       if (dartReceiver != null && abstractReceiver.isNullable) {
@@ -518,17 +517,17 @@
         variable.type = value.definition.type;
       }
       if (invoke.callingConvention == CallingConvention.Intercepted) {
-        setValue(function.thisParameter, invoke.receiver);
+        setValue(function.thisParameter, invoke.receiverRef);
         function.parameters[0].type = abstractReceiverInMethod;
-        for (int i = 1; i < invoke.arguments.length; ++i) {
-          setValue(function.parameters[i], invoke.arguments[i]);
+        for (int i = 1; i < invoke.argumentRefs.length; ++i) {
+          setValue(function.parameters[i], invoke.argumentRefs[i]);
         }
       } else {
-        if (invoke.receiver != null) {
+        if (invoke.receiverRef != null) {
           function.thisParameter.type = abstractReceiverInMethod;
         }
-        for (int i = 0; i < invoke.arguments.length; ++i) {
-          setValue(function.parameters[i], invoke.arguments[i]);
+        for (int i = 0; i < invoke.argumentRefs.length; ++i) {
+          setValue(function.parameters[i], invoke.argumentRefs[i]);
         }
       }
       optimizeBeforeInlining(function);
diff --git a/pkg/compiler/lib/src/cps_ir/insert_refinements.dart b/pkg/compiler/lib/src/cps_ir/insert_refinements.dart
index 207753f..ef291b1 100644
--- a/pkg/compiler/lib/src/cps_ir/insert_refinements.dart
+++ b/pkg/compiler/lib/src/cps_ir/insert_refinements.dart
@@ -74,7 +74,7 @@
   }
 
   Primitive unfoldInterceptor(Primitive prim) {
-    return prim is Interceptor ? prim.input.definition : prim;
+    return prim is Interceptor ? prim.input : prim;
   }
 
   /// Sets [refined] to be the current refinement for its value, and pushes an
@@ -128,19 +128,19 @@
   }
 
   void visitInvokeStatic(InvokeStatic node) {
-    node.arguments.forEach(processReference);
+    node.argumentRefs.forEach(processReference);
     _refineArguments(node,
         _getSuccessTypesForStaticMethod(types, node.target));
   }
 
   void visitInvokeMethod(InvokeMethod node) {
     // Update references to their current refined values.
-    processReference(node.receiver);
-    node.arguments.forEach(processReference);
+    processReference(node.receiverRef);
+    node.argumentRefs.forEach(processReference);
 
     // If the call is intercepted, we want to refine the actual receiver,
     // not the interceptor.
-    Primitive receiver = unfoldInterceptor(node.receiver.definition);
+    Primitive receiver = unfoldInterceptor(node.receiver);
 
     // Do not try to refine the receiver of closure calls; the class world
     // does not know about closure classes.
@@ -160,10 +160,10 @@
   }
 
   void visitTypeCast(TypeCast node) {
-    Primitive value = node.value.definition;
+    Primitive value = node.value;
 
-    processReference(node.value);
-    node.typeArguments.forEach(processReference);
+    processReference(node.valueRef);
+    node.typeArgumentRefs.forEach(processReference);
 
     // Refine the type of the input.
     TypeMask type = types.subtypesOf(node.dartType).nullable();
@@ -191,11 +191,11 @@
   }
 
   void visitBranch(Branch node) {
-    processReference(node.condition);
-    Primitive condition = node.condition.definition;
+    processReference(node.conditionRef);
+    Primitive condition = node.condition;
 
-    Continuation trueCont = node.trueContinuation.definition;
-    Continuation falseCont = node.falseContinuation.definition;
+    Continuation trueCont = node.trueContinuation;
+    Continuation falseCont = node.falseContinuation;
 
     // Sink both continuations to the Branch to ensure everything in scope
     // here is also in scope inside the continuations.
@@ -204,7 +204,7 @@
 
     // If the condition is an 'is' check, promote the checked value.
     if (condition is TypeTest) {
-      Primitive value = condition.value.definition;
+      Primitive value = condition.value;
       TypeMask type = types.subtypesOf(condition.dartType);
       Primitive refinedValue = new Refinement(value, type);
       pushRefinement(trueCont, refinedValue);
@@ -246,8 +246,8 @@
 
     if (condition is ApplyBuiltinOperator &&
         condition.operator == BuiltinOperator.Identical) {
-      refineEquality(condition.arguments[0].definition,
-                     condition.arguments[1].definition,
+      refineEquality(condition.argument(0),
+                     condition.argument(1),
                      trueCont,
                      falseCont);
       return;
diff --git a/pkg/compiler/lib/src/cps_ir/loop_effects.dart b/pkg/compiler/lib/src/cps_ir/loop_effects.dart
index c7680b0..4a73e5d 100644
--- a/pkg/compiler/lib/src/cps_ir/loop_effects.dart
+++ b/pkg/compiler/lib/src/cps_ir/loop_effects.dart
@@ -2,25 +2,16 @@
 
 import 'cps_ir_nodes.dart';
 import 'loop_hierarchy.dart';
-import '../universe/side_effects.dart';
-import '../elements/elements.dart';
 import '../world.dart';
+import 'effects.dart';
 
-/// Determines which the [SideEffects] that may occur during each loop in
-/// a given function, in addition to whether the loop may change the length
-/// of an indexable object.
-///
-/// TODO(asgerf): Make length a flag on [SideEffects] for better precision and
-/// so we don't need to special case the length in this class.
+/// Determines the side effects that may occur in each loop.
 class LoopSideEffects extends TrampolineRecursiveVisitor {
   LoopHierarchy loopHierarchy;
   final World world;
   final Map<Continuation, List<Continuation>> exitContinuations = {};
-  final Map<Continuation, SideEffects> loopSideEffects = {};
-  final Set<Continuation> loopsChangingLength = new Set<Continuation>();
+  final Map<Continuation, int> loopSideEffects = {};
   Continuation currentLoopHeader;
-  SideEffects currentLoopSideEffects = new SideEffects.empty();
-  bool currentLoopChangesLength = false;
 
   LoopSideEffects(FunctionDefinition node, this.world, {this.loopHierarchy}) {
     if (loopHierarchy == null) {
@@ -31,30 +22,25 @@
 
   /// Returns the accumulated effects and dependencies on all paths from the
   /// loop entry to any recursive invocation of the loop.
-  SideEffects getSideEffectsInLoop(Continuation loop) {
+  int getSideEffectsInLoop(Continuation loop) {
     return loopSideEffects[loop];
   }
 
   /// True if the length of an indexable object may change between the loop
   /// entry and a recursive invocation of the loop.
-  bool loopChangesLength(Continuation loop) {
-    return loopsChangingLength.contains(loop);
+  bool changesIndexableLength(Continuation loop) {
+    return loopSideEffects[loop] & Effects.changesIndexableLength != 0;
   }
 
   @override
   Expression traverseContinuation(Continuation cont) {
     if (cont.isRecursive) {
-      SideEffects oldEffects = currentLoopSideEffects;
-      bool oldChangesLength = currentLoopChangesLength;
-      loopSideEffects[cont] = currentLoopSideEffects = new SideEffects.empty();
+      loopSideEffects[cont] = Effects.none;
       exitContinuations[cont] = <Continuation>[];
       pushAction(() {
-        oldEffects.add(currentLoopSideEffects);
-        if (currentLoopChangesLength) {
-          loopsChangingLength.add(cont);
+        if (currentLoopHeader != null) {
+          loopSideEffects[currentLoopHeader] |= loopSideEffects[cont];
         }
-        currentLoopChangesLength = currentLoopChangesLength || oldChangesLength;
-        currentLoopSideEffects = oldEffects;
         exitContinuations[cont].forEach(push);
       });
     }
@@ -78,6 +64,14 @@
     return node.body;
   }
 
+  @override
+  Expression traverseLetPrim(LetPrim node) {
+    if (currentLoopHeader != null) {
+      loopSideEffects[currentLoopHeader] |= node.primitive.effects;
+    }
+    return node.body;
+  }
+
   void enqueueContinuation(Continuation cont) {
     Continuation loop = loopHierarchy.getEnclosingLoop(cont);
     if (loop == currentLoopHeader) {
@@ -101,85 +95,4 @@
       exitContinuations[inner].add(cont);
     }
   }
-
-  void addSideEffects(SideEffects effects) {
-    currentLoopSideEffects.add(effects);
-    if (effects.changesIndex()) {
-      currentLoopChangesLength = true;
-    }
-  }
-
-  void addAllSideEffects() {
-    currentLoopSideEffects.setAllSideEffects();
-    currentLoopSideEffects.setDependsOnSomething();
-    currentLoopChangesLength = true;
-  }
-
-  void visitInvokeMethod(InvokeMethod node) {
-    addSideEffects(world.getSideEffectsOfSelector(node.selector, node.mask));
-  }
-
-  void visitInvokeStatic(InvokeStatic node) {
-    addSideEffects(world.getSideEffectsOfElement(node.target));
-  }
-
-  void visitInvokeMethodDirectly(InvokeMethodDirectly node) {
-    FunctionElement target = node.target;
-    if (target is ConstructorBodyElement) {
-      ConstructorBodyElement body = target;
-      target = body.constructor;
-    }
-    addSideEffects(world.getSideEffectsOfElement(target));
-  }
-
-  void visitInvokeConstructor(InvokeConstructor node) {
-    addSideEffects(world.getSideEffectsOfElement(node.target));
-  }
-
-  void visitSetStatic(SetStatic node) {
-    currentLoopSideEffects.setChangesStaticProperty();
-  }
-
-  void visitGetStatic(GetStatic node) {
-    currentLoopSideEffects.setDependsOnStaticPropertyStore();
-  }
-
-  void visitGetField(GetField node) {
-    currentLoopSideEffects.setDependsOnInstancePropertyStore();
-  }
-
-  void visitSetField(SetField node) {
-    currentLoopSideEffects.setChangesInstanceProperty();
-  }
-
-  void visitGetIndex(GetIndex node) {
-    currentLoopSideEffects.setDependsOnIndexStore();
-  }
-
-  void visitSetIndex(SetIndex node) {
-    // Set the change index flag without setting the change length flag.
-    currentLoopSideEffects.setChangesIndex();
-  }
-
-  void visitForeignCode(ForeignCode node) {
-    addSideEffects(node.nativeBehavior.sideEffects);
-  }
-
-  void visitGetLazyStatic(GetLazyStatic node) {
-    // TODO(asgerf): How do we get the side effects of a lazy field initializer?
-    addAllSideEffects();
-  }
-
-  void visitAwait(Await node) {
-    addAllSideEffects();
-  }
-
-  void visitYield(Yield node) {
-    addAllSideEffects();
-  }
-
-  void visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
-    currentLoopSideEffects.setChangesIndex();
-    currentLoopChangesLength = true; // Push and pop.
-  }
 }
diff --git a/pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart b/pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart
index 897a44e..57d71207 100644
--- a/pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart
+++ b/pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart
@@ -118,14 +118,14 @@
     Continuation target;
     if (node is InvokeContinuation) {
       if (node.isRecursive) {
-        target = node.continuation.definition;
+        target = node.continuation;
       } else {
-        target = loopTarget[node.continuation.definition];
+        target = loopTarget[node.continuation];
       }
     } else if (node is Branch) {
       target = _markInnerLoop(
-          loopTarget[node.trueContinuation.definition],
-          loopTarget[node.falseContinuation.definition]);
+          loopTarget[node.trueContinuation],
+          loopTarget[node.falseContinuation]);
     } else if (node == null) {
       // If the code ends abruptly, use the exit loop provided in [update].
       target = _exitLoop;
diff --git a/pkg/compiler/lib/src/cps_ir/loop_invariant_branch.dart b/pkg/compiler/lib/src/cps_ir/loop_invariant_branch.dart
index e9f04a6..98df30a 100644
--- a/pkg/compiler/lib/src/cps_ir/loop_invariant_branch.dart
+++ b/pkg/compiler/lib/src/cps_ir/loop_invariant_branch.dart
@@ -121,7 +121,7 @@
       Node use = ref.parent;
       if (use is InvokeContinuation) {
         for (Parameter loopParam in parameters) {
-          use.arguments.add(new Reference<Primitive>(loopParam)..parent = use);
+          use.argumentRefs.add(new Reference<Primitive>(loopParam)..parent = use);
         }
       }
     }
@@ -134,11 +134,11 @@
     Branch branch = body;
 
     // Is the condition loop invariant?
-    Primitive condition = branch.condition.definition;
+    Primitive condition = branch.condition;
     if (loopHeaderFor[condition] == loop) return false;
 
-    Continuation trueCont = branch.trueContinuation.definition;
-    Continuation falseCont = branch.falseContinuation.definition;
+    Continuation trueCont = branch.trueContinuation;
+    Continuation falseCont = branch.falseContinuation;
     Continuation hoistedCase; // The branch to hoist.
     Continuation loopCase; // The branch that is part of the loop.
 
@@ -212,7 +212,7 @@
     //
     InvokeContinuation loopEntry = loopBinding.body;
     List<Primitive> loopArgs =
-        loopEntry.arguments.map((ref) => ref.definition).toList();
+        loopEntry.arguments.toList();
     CpsFragment cps = new CpsFragment();
     cps.branch(condition,
           strict: branch.isStrictCheck,
diff --git a/pkg/compiler/lib/src/cps_ir/mutable_ssa.dart b/pkg/compiler/lib/src/cps_ir/mutable_ssa.dart
index e5ea7a8..0c86696 100644
--- a/pkg/compiler/lib/src/cps_ir/mutable_ssa.dart
+++ b/pkg/compiler/lib/src/cps_ir/mutable_ssa.dart
@@ -39,7 +39,7 @@
   }
 
   void processSetMutable(SetMutable node) {
-    MutableVariable variable = node.variable.definition;
+    MutableVariable variable = node.variable;
     if (currentDepth > variableDepth[variable]) {
       hasAssignmentInTry.add(variable);
     }
@@ -142,29 +142,29 @@
         stack.add(new VariableItem());
 
         // Put the initial value into the environment.
-        Primitive value = node.value.definition;
+        Primitive value = node.value;
         environment[node.variable] = value;
 
         // Preserve variable names.
         mergeHints(node.variable, value);
 
         // Remove the mutable variable binding.
-        node.value.unlink();
+        node.valueRef.unlink();
         node.remove();
       } else if (node is LetPrim && node.primitive is SetMutable) {
         SetMutable setter = node.primitive;
-        MutableVariable variable = setter.variable.definition;
+        MutableVariable variable = setter.variable;
         if (shouldRewrite(variable)) {
           // As above, update the environment, preserve variables and remove
           // the mutable variable assignment.
-          environment[variable] = setter.value.definition;
-          mergeHints(variable, setter.value.definition);
-          setter.value.unlink();
+          environment[variable] = setter.value;
+          mergeHints(variable, setter.value);
+          setter.valueRef.unlink();
           node.remove();
         }
       } else if (node is LetPrim && node.primitive is GetMutable) {
         GetMutable getter = node.primitive;
-        MutableVariable variable = getter.variable.definition;
+        MutableVariable variable = getter.variable;
         if (shouldRewrite(variable)) {
           // Replace with the reaching definition from the environment.
           Primitive value = environment[variable];
@@ -206,7 +206,7 @@
 
     // Analyze the terminal node.
     if (node is InvokeContinuation) {
-      Continuation cont = node.continuation.definition;
+      Continuation cont = node.continuation;
       if (cont.isReturnContinuation) return;
       // This is a call to a join continuation. Add arguments for the phi
       // parameters that were added to this continuation.
@@ -214,7 +214,7 @@
       for (int i = 0; i < phiCount; ++i) {
         Primitive value = environment[mutableVariables[i]];
         Reference<Primitive> arg = new Reference<Primitive>(value);
-        node.arguments.add(arg);
+        node.argumentRefs.add(arg);
         arg.parent = node;
       }
     } else if (node is Branch) {
@@ -222,10 +222,10 @@
       // Clone the environments once so the processing of one branch does not
       // mutate the environment needed to process the other branch.
       stack.add(new ContinuationItem(
-          node.trueContinuation.definition,
+          node.trueContinuation,
           new Map<MutableVariable, Primitive>.from(environment)));
       stack.add(new ContinuationItem(
-          node.falseContinuation.definition,
+          node.falseContinuation,
           environment));
     } else {
       assert(node is Throw || node is Unreachable);
diff --git a/pkg/compiler/lib/src/cps_ir/optimize_interceptors.dart b/pkg/compiler/lib/src/cps_ir/optimize_interceptors.dart
index 689dac6..d9c59b6 100644
--- a/pkg/compiler/lib/src/cps_ir/optimize_interceptors.dart
+++ b/pkg/compiler/lib/src/cps_ir/optimize_interceptors.dart
@@ -137,7 +137,7 @@
     for (Reference ref = node.firstRef; ref != null; ref = ref.next) {
       if (ref.parent is InvokeMethod) {
         InvokeMethod invoke = ref.parent;
-        if (invoke.receiver != ref) return false;
+        if (invoke.receiverRef != ref) return false;
         var interceptedClasses =
             backend.getInterceptedClassesOn(invoke.selector.name);
         if (interceptedClasses.contains(helpers.jsDoubleClass)) return false;
@@ -173,7 +173,7 @@
     // TODO(asgerf): This could be more precise if we used the use-site type,
     // since the interceptor may have been hoisted out of a loop, where a less
     // precise type is known.
-    Primitive input = node.input.definition;
+    Primitive input = node.input;
     TypeMask type = input.type;
     if (canInterceptNull(node)) return null;
     type = type.nonNullable();
@@ -198,7 +198,7 @@
   /// successful.
   bool constifyInterceptor(Interceptor interceptor) {
     LetPrim let = interceptor.parent;
-    Primitive input = interceptor.input.definition;
+    Primitive input = interceptor.input;
     ClassElement classElement = getSingleInterceptorClass(interceptor);
 
     if (classElement == null) return false;
@@ -261,7 +261,7 @@
   @override
   void visitInvokeMethod(InvokeMethod node) {
     if (node.callingConvention != CallingConvention.Intercepted) return;
-    Primitive interceptor = node.receiver.definition;
+    Primitive interceptor = node.receiver;
     if (interceptor is! Interceptor ||
         interceptor.hasMultipleUses ||
         loopHeaderFor[interceptor] != currentLoopHeader) {
@@ -270,12 +270,12 @@
     // TODO(asgerf): Consider heuristics for when to use one-shot interceptors.
     //   E.g. using only one-shot interceptors with a fast path.
     node.callingConvention = CallingConvention.OneShotIntercepted;
-    node..receiver.unlink()..receiver = node.arguments.removeAt(0);
+    node..receiverRef.unlink()..receiverRef = node.argumentRefs.removeAt(0);
   }
 
   @override
   void visitTypeTestViaFlag(TypeTestViaFlag node) {
-    Primitive interceptor = node.interceptor.definition;
+    Primitive interceptor = node.interceptor;
     if (interceptor is! Interceptor ||
         interceptor.hasMultipleUses ||
         loopHeaderFor[interceptor] != currentLoopHeader ||
@@ -283,7 +283,7 @@
       return;
     }
     Interceptor inter = interceptor;
-    Primitive value = inter.input.definition;
+    Primitive value = inter.input;
     node.replaceWith(new TypeTest(value, node.dartType, [])..type = node.type);
   }
 }
diff --git a/pkg/compiler/lib/src/cps_ir/path_based_optimizer.dart b/pkg/compiler/lib/src/cps_ir/path_based_optimizer.dart
index 6f9fac5..aed13e6 100644
--- a/pkg/compiler/lib/src/cps_ir/path_based_optimizer.dart
+++ b/pkg/compiler/lib/src/cps_ir/path_based_optimizer.dart
@@ -117,7 +117,7 @@
   }
 
   void visitInvokeContinuation(InvokeContinuation node) {
-    Continuation cont = node.continuation.definition;
+    Continuation cont = node.continuation;
     if (cont.isReturnContinuation) return;
     if (node.isRecursive) return;
     Map<Primitive, int> target = valuesAt[cont];
@@ -131,9 +131,9 @@
   }
 
   visitBranch(Branch node) {
-    Primitive condition = node.condition.definition.effectiveDefinition;
-    Continuation trueCont = node.trueContinuation.definition;
-    Continuation falseCont = node.falseContinuation.definition;
+    Primitive condition = node.condition.effectiveDefinition;
+    Continuation trueCont = node.trueContinuation;
+    Continuation falseCont = node.falseContinuation;
     if (condition.hasExactlyOneUse) {
       // Handle common case specially. Do not add [condition] to the map if
       // there are no other uses.
@@ -167,7 +167,7 @@
       // self-interceptor.
       // TODO(25646): If TypeMasks could represent "any self-interceptor" this
       //   optimization should be subsumed by type propagation.
-      node.receiver.changeTo(node.dartReceiver);
+      node.receiverRef.changeTo(node.dartReceiver);
 
       // Replace the extra receiver argument with a dummy value if the
       // target definitely does not use it.
@@ -176,7 +176,7 @@
         Constant dummy = new Constant(new IntConstantValue(0))
             ..type = typeSystem.intType;
         new LetPrim(dummy).insertAbove(node.parent);
-        node.arguments[0].changeTo(dummy);
+        node.argumentRefs[0].changeTo(dummy);
         node.callingConvention = CallingConvention.DummyIntercepted;
       }
     }
diff --git a/pkg/compiler/lib/src/cps_ir/redundant_join.dart b/pkg/compiler/lib/src/cps_ir/redundant_join.dart
index f1191ff..59cac26 100644
--- a/pkg/compiler/lib/src/cps_ir/redundant_join.dart
+++ b/pkg/compiler/lib/src/cps_ir/redundant_join.dart
@@ -19,7 +19,8 @@
 /// one continuation. The reference chains for parameters are therefore
 /// meaningless during this pass, until repaired by [AlphaRenamer] at
 /// the end.
-class RedundantJoinEliminator extends TrampolineRecursiveVisitor implements Pass {
+class RedundantJoinEliminator extends TrampolineRecursiveVisitor
+      implements Pass {
   String get passName => 'Redundant join elimination';
 
   final Set<Branch> workSet = new Set<Branch>();
@@ -80,7 +81,7 @@
     // enclosing continuation.
     // Note: Do not use the parent pointer for this check, because parameters
     // are temporarily shared between different continuations during this pass.
-    Primitive condition = branch.condition.definition;
+    Primitive condition = branch.condition;
     int parameterIndex = branchCont.parameters.indexOf(condition);
     if (parameterIndex == -1) return;
 
@@ -92,7 +93,7 @@
     InvokeContinuation trueCall, falseCall;
     for (Reference ref = branchCont.firstRef; ref != null; ref = ref.next) {
       InvokeContinuation invoke = ref.parent;
-      Primitive argument = invoke.arguments[parameterIndex].definition;
+      Primitive argument = invoke.argument(parameterIndex);
       if (argument is! Constant) return; // Branching condition is unknown.
       Constant constant = argument;
       if (isTruthyConstant(constant.value, strict: branch.isStrictCheck)) {
@@ -139,7 +140,8 @@
           Expression use = ref.parent;
           if (use is InvokeContinuation) {
             for (Parameter param in branchCont.parameters) {
-              use.arguments.add(new Reference<Primitive>(param)..parent = use);
+              use.argumentRefs.add(
+                  new Reference<Primitive>(param)..parent = use);
             }
           } else {
             // The branch will be eliminated, so don't worry about updating it.
@@ -153,8 +155,8 @@
 
     assert(branchCont.body == branch);
 
-    Continuation trueCont = branch.trueContinuation.definition;
-    Continuation falseCont = branch.falseContinuation.definition;
+    Continuation trueCont = branch.trueContinuation;
+    Continuation falseCont = branch.falseContinuation;
 
     assert(branchCont != trueCont);
     assert(branchCont != falseCont);
@@ -168,19 +170,19 @@
     while (branchCont.firstRef != null) {
       Reference reference = branchCont.firstRef;
       InvokeContinuation invoke = branchCont.firstRef.parent;
-      Constant condition = invoke.arguments[parameterIndex].definition;
+      Constant condition = invoke.argument(parameterIndex);
       if (isTruthyConstant(condition.value, strict: branch.isStrictCheck)) {
-        invoke.continuation.changeTo(trueCont);
+        invoke.continuationRef.changeTo(trueCont);
       } else {
-        invoke.continuation.changeTo(falseCont);
+        invoke.continuationRef.changeTo(falseCont);
       }
       assert(branchCont.firstRef != reference);
     }
 
     // Remove the now-unused branchCont continuation.
     assert(branchCont.hasNoUses);
-    branch.trueContinuation.unlink();
-    branch.falseContinuation.unlink();
+    branch.trueContinuationRef.unlink();
+    branch.falseContinuationRef.unlink();
     outerLetCont.continuations.remove(branchCont);
     if (outerLetCont.continuations.isEmpty) {
       outerLetCont.remove();
diff --git a/pkg/compiler/lib/src/cps_ir/redundant_phi.dart b/pkg/compiler/lib/src/cps_ir/redundant_phi.dart
index f5d5423..b612d13 100644
--- a/pkg/compiler/lib/src/cps_ir/redundant_phi.dart
+++ b/pkg/compiler/lib/src/cps_ir/redundant_phi.dart
@@ -47,7 +47,7 @@
     List<InvokeContinuation> invokes = <InvokeContinuation>[];
     for (Reference ref = cont.firstRef; ref != null; ref = ref.next) {
       Node parent = ref.parent;
-      if (parent is InvokeContinuation && ref == parent.continuation) {
+      if (parent is InvokeContinuation && ref == parent.continuationRef) {
         invokes.add(parent);
       } else {
         return; // Can't optimize.
@@ -64,7 +64,7 @@
     Primitive uniqueDefinitionOf(int i) {
       Primitive value = null;
       for (InvokeContinuation invoke in invokes) {
-        Primitive def = invoke.arguments[i].definition.effectiveDefinition;
+        Primitive def = invoke.argument(i).effectiveDefinition;
 
         if (cont.parameters[i] == def) {
           // Invocation param == param in LetCont (i.e. a recursive call).
@@ -110,7 +110,7 @@
         if (src != dst) {
           cont.parameters[dst] = cont.parameters[src];
           for (InvokeContinuation invoke in invokes) {
-            invoke.arguments[dst] = invoke.arguments[src];
+            invoke.argumentRefs[dst] = invoke.argumentRefs[src];
           }
         }
         dst++;
@@ -126,7 +126,7 @@
            ref = ref.next) {
         Node parent = ref.parent;
         if (parent is InvokeContinuation) {
-          Continuation thatCont = parent.continuation.definition;
+          Continuation thatCont = parent.continuation;
           if (thatCont != cont) {
             workSet.add(thatCont);
           }
@@ -140,7 +140,7 @@
       //   arguments are unlinked to keep definition usages up to date.
       oldDefinition.replaceUsesWith(uniqueDefinition);
       for (InvokeContinuation invoke in invokes) {
-        invoke.arguments[src].unlink();
+        invoke.argumentRefs[src].unlink();
       }
 
       // Finally, if the substituted definition is not in scope of the affected
@@ -156,7 +156,7 @@
     // Remove trailing items from parameter and argument lists.
     cont.parameters.length = dst;
     for (InvokeContinuation invoke in invokes) {
-      invoke.arguments.length = dst;
+      invoke.argumentRefs.length = dst;
     }
   }
 
diff --git a/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart b/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart
index b220847..5eb8156 100644
--- a/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart
+++ b/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart
@@ -77,7 +77,7 @@
     for (Reference ref = allocation.firstRef; ref != null; ref = ref.next) {
       Node use = ref.parent;
       if (use is GetField) continue;
-      if (use is SetField && use.object == ref) continue;
+      if (use is SetField && use.objectRef == ref) continue;
       return;
     }
 
@@ -102,7 +102,7 @@
       int i = 0;
       allocation.classElement.forEachInstanceField(
         (ClassElement enclosingClass, FieldElement field) {
-          Primitive argument = allocation.arguments[i++].definition;
+          Primitive argument = allocation.argument(i++);
           fieldInitialValues[field] = argument;
         },
         includeSuperAndInjectedMembers: true);
@@ -127,7 +127,7 @@
         insertionPoint = let..insertBelow(insertionPoint);
       }
       LetMutable let = new LetMutable(variable, initialValue);
-      let.value.parent = let;
+      let.valueRef.parent = let;
       insertionPoint = let..insertBelow(insertionPoint);
     }
 
@@ -141,7 +141,7 @@
         if (variable != null) {
           GetMutable getter = new GetMutable(variable);
           getter.type = getField.type;
-          getter.variable.parent = getter;
+          getter.variableRef.parent = getter;
           getField.replaceUsesWith(getter);
           replacePrimitive(getField, getter);
           deletePrimitive(getField);
@@ -150,14 +150,14 @@
           getField.replaceUsesWith(value);
           deleteLetPrimOf(getField);
         }
-      } else if (use is SetField && use.object == ref) {
+      } else if (use is SetField && use.objectRef == ref) {
         SetField setField = use;
         MutableVariable variable = cells[setField.field];
-        Primitive value = setField.value.definition;
+        Primitive value = setField.value;
         variable.type = variable.type.union(value.type, classWorld);
         SetMutable setter = new SetMutable(variable, value);
-        setter.variable.parent = setter;
-        setter.value.parent = setter;
+        setter.variableRef.parent = setter;
+        setter.valueRef.parent = setter;
         setField.replaceUsesWith(setter);
         replacePrimitive(setField, setter);
         deletePrimitive(setField);
diff --git a/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart b/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart
index 298a082..1c84ca6 100644
--- a/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart
+++ b/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart
@@ -203,9 +203,9 @@
     cont.body = null;
 
     // Substitute the invocation argument for the continuation parameter.
-    for (int i = 0; i < invoke.arguments.length; i++) {
+    for (int i = 0; i < invoke.argumentRefs.length; i++) {
       Parameter param = cont.parameters[i];
-      Primitive argument = invoke.arguments[i].definition;
+      Primitive argument = invoke.argument(i);
       param.replaceUsesWith(argument);
       argument.useElementAsHint(param.hint);
       _checkConstantBranchCondition(argument);
@@ -243,7 +243,7 @@
     _removeContinuation(cont);
 
     InvokeContinuation invoke = cont.body;
-    Continuation wrappedCont = invoke.continuation.definition;
+    Continuation wrappedCont = invoke.continuation;
 
     for (int i = 0; i < cont.parameters.length; ++i) {
       wrappedCont.parameters[i].useElementAsHint(cont.parameters[i].hint);
@@ -280,13 +280,13 @@
     // branch is deleted the other target becomes unreferenced and the chosen
     // target becomes available for eta-cont and further reductions.
     Continuation target;
-    Primitive condition = branch.condition.definition;
+    Primitive condition = branch.condition;
     if (condition is Constant) {
       target = isTruthyConstant(condition.value, strict: branch.isStrictCheck)
-          ? branch.trueContinuation.definition
-          : branch.falseContinuation.definition;
-    } else if (_isBranchTargetOfUselessIf(branch.trueContinuation.definition)) {
-      target = branch.trueContinuation.definition;
+          ? branch.trueContinuation
+          : branch.falseContinuation;
+    } else if (_isBranchTargetOfUselessIf(branch.trueContinuation)) {
+      target = branch.trueContinuation;
     } else {
       return;
     }
@@ -331,9 +331,9 @@
     // Remove the index'th argument from each invocation.
     for (Reference ref = continuation.firstRef; ref != null; ref = ref.next) {
       InvokeContinuation invoke = ref.parent;
-      Reference<Primitive> argument = invoke.arguments[index];
+      Reference<Primitive> argument = invoke.argumentRefs[index];
       argument.unlink();
-      invoke.arguments.removeAt(index);
+      invoke.argumentRefs.removeAt(index);
       // Removing an argument can create a dead primitive or an eta-redex
       // in case the parent is a continuation that now has matching parameters.
       _checkDeadPrimitive(argument.definition);
@@ -449,7 +449,7 @@
   }
 
   InvokeContinuation invoke = cont.body;
-  Continuation invokedCont = invoke.continuation.definition;
+  Continuation invokedCont = invoke.continuation;
 
   // Do not eta-reduce return join-points since the direct-style code is worse
   // in the common case (i.e. returns are moved inside `if` branches).
@@ -487,14 +487,14 @@
   //
   // TODO(kmillikin): find real occurrences of these patterns, and see if they
   // can be optimized.
-  if (cont.parameters.length != invoke.arguments.length) {
+  if (cont.parameters.length != invoke.argumentRefs.length) {
     return false;
   }
 
   // TODO(jgruber): Linear in the parameter count. Can be improved to near
   // constant time by using union-find data structure.
   for (int i = 0; i < cont.parameters.length; i++) {
-    if (invoke.arguments[i].definition != cont.parameters[i]) {
+    if (invoke.argument(i) != cont.parameters[i]) {
       return false;
     }
   }
@@ -513,7 +513,7 @@
 }
 
 bool _isBranchRedex(Branch branch) {
-  return _isUselessIf(branch) || branch.condition.definition is Constant;
+  return _isUselessIf(branch) || branch.condition is Constant;
 }
 
 bool _isBranchTargetOfUselessIf(Continuation cont) {
@@ -533,16 +533,16 @@
 }
 
 bool _isUselessIf(Branch branch) {
-  Continuation trueCont = branch.trueContinuation.definition;
+  Continuation trueCont = branch.trueContinuation;
   Expression trueBody = _unfoldDeadRefinements(trueCont.body);
   if (trueBody is! InvokeContinuation) return false;
-  Continuation falseCont = branch.falseContinuation.definition;
+  Continuation falseCont = branch.falseContinuation;
   Expression falseBody = _unfoldDeadRefinements(falseCont.body);
   if (falseBody is! InvokeContinuation) return false;
   InvokeContinuation trueInvoke = trueBody;
   InvokeContinuation falseInvoke = falseBody;
-  if (trueInvoke.continuation.definition !=
-      falseInvoke.continuation.definition) {
+  if (trueInvoke.continuation !=
+      falseInvoke.continuation) {
     return false;
   }
   // Matching zero arguments should be adequate, since isomorphic true and false
@@ -553,7 +553,7 @@
   // dead parameter reduction, where some but not all of the invocations have
   // been rewritten.  In that case, we will find the redex (once) after both
   // of these invocations have been rewritten.
-  return trueInvoke.arguments.isEmpty && falseInvoke.arguments.isEmpty;
+  return trueInvoke.argumentRefs.isEmpty && falseInvoke.argumentRefs.isEmpty;
 }
 
 bool _isDeadParameter(Parameter parameter) {
diff --git a/pkg/compiler/lib/src/cps_ir/type_propagation.dart b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
index 00cbfb1..6b09771 100644
--- a/pkg/compiler/lib/src/cps_ir/type_propagation.dart
+++ b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
@@ -38,6 +38,7 @@
 import 'cps_fragment.dart';
 import 'cps_ir_nodes.dart';
 import 'type_mask_system.dart';
+import 'effects.dart';
 
 class ConstantPropagationLattice {
   final TypeMaskSystem typeSystem;
@@ -960,10 +961,10 @@
 
   bool isAlwaysThrowingOrDiverging(Primitive prim) {
     if (prim is SetField) {
-      return getValue(prim.object.definition).isNullConstant;
+      return getValue(prim.object).isNullConstant;
     }
     if (prim is SetIndex) {
-      return getValue(prim.object.definition).isNullConstant;
+      return getValue(prim.object).isNullConstant;
     }
     // If a primitive has a value, but can't return anything, it must throw
     // or diverge.
@@ -1077,9 +1078,9 @@
   //
   // (Branch (IsTrue true) k0 k1) -> (InvokeContinuation k0)
   void visitBranch(Branch node) {
-    Continuation trueCont = node.trueContinuation.definition;
-    Continuation falseCont = node.falseContinuation.definition;
-    Primitive condition = node.condition.definition;
+    Continuation trueCont = node.trueContinuation;
+    Continuation falseCont = node.falseContinuation;
+    Primitive condition = node.condition;
     AbstractConstantValue conditionValue = getValue(condition);
 
     // Change to non-strict check if the condition is a boolean or null.
@@ -1110,9 +1111,9 @@
     // a negation again if that's useful.
     if (condition is ApplyBuiltinOperator &&
         condition.operator == BuiltinOperator.IsFalsy) {
-      node.condition.changeTo(condition.arguments.single.definition);
-      node.trueContinuation.changeTo(falseCont);
-      node.falseContinuation.changeTo(trueCont);
+      node.conditionRef.changeTo(condition.argument(0));
+      node.trueContinuationRef.changeTo(falseCont);
+      node.falseContinuationRef.changeTo(trueCont);
       return;
     }
   }
@@ -1123,19 +1124,19 @@
     // pass, but doing it here helps simplify pattern matching code, since the
     // effective definition of a primitive can then be found without going
     // through redundant InvokeContinuations.
-    Continuation cont = node.continuation.definition;
+    Continuation cont = node.continuation;
     if (cont.hasExactlyOneUse &&
         !cont.isReturnContinuation &&
         !cont.isRecursive &&
         !node.isEscapingTry) {
-      for (int i = 0; i < node.arguments.length; ++i) {
-        Primitive argument = node.arguments[i].definition;
+      for (int i = 0; i < node.argumentRefs.length; ++i) {
+        Primitive argument = node.argument(i);
         Parameter parameter = cont.parameters[i];
         argument.useElementAsHint(parameter.hint);
         parameter.replaceUsesWith(argument);
-        node.arguments[i].unlink();
+        node.argumentRefs[i].unlink();
       }
-      node.continuation.unlink();
+      node.continuationRef.unlink();
       InteriorNode parent = node.parent;
       Expression body = cont.body;
       parent.body = body;
@@ -1278,10 +1279,10 @@
 
     /// Replaces the call with a call to [name] with the same inputs.
     InvokeMethod makeRenamedInvoke(String name) {
-      return new InvokeMethod(node.receiver.definition,
+      return new InvokeMethod(node.receiver,
           renameToOptimizedSelector(name),
           node.mask,
-          node.arguments.map((ref) => ref.definition).toList(),
+          node.arguments.toList(),
           sourceInformation: node.sourceInformation,
           callingConvention: node.callingConvention);
     }
@@ -1522,8 +1523,38 @@
     }
     switch (node.selector.name) {
       case 'length':
-        if (!node.selector.isGetter) return null;
-        return new GetLength(receiver);
+        if (node.selector.isGetter) {
+          return new GetLength(receiver);
+        }
+        if (node.selector.isSetter) {
+          if (!typeSystem.isDefinitelyExtendableArray(receiver.type,
+                allowNull: true)) {
+            return null;
+          }
+          CpsFragment cps = new CpsFragment(node.sourceInformation);
+          Primitive newLength = node.dartArgument(0);
+          if (!typeSystem.isDefinitelyUint(newLength.type)) {
+            // TODO(asgerf): We could let the SetLength instruction throw for
+            // negative right-hand sides (see length setter in js_array.dart).
+            if (compiler.trustPrimitives) {
+              newLength = cps.refine(newLength, typeSystem.uint32Type);
+              newLength.type = typeSystem.uint32Type;
+            } else {
+              return null;
+            }
+          }
+          cps.letPrim(new ApplyBuiltinMethod(
+              BuiltinMethod.SetLength,
+              receiver,
+              [newLength],
+              node.sourceInformation));
+          if (!typeSystem.isDefinitelyUint32(newLength.type)) {
+            // If the setter succeeded, the length must have been a uint32.
+            cps.refine(newLength, typeSystem.uint32Type);
+          }
+          return cps;
+        }
+        return null;
 
       case '[]':
         Primitive index = node.dartArgument(0);
@@ -1640,7 +1671,7 @@
         }
         LiteralList addedLiteral = addedList;
         CpsFragment cps = new CpsFragment(sourceInfo);
-        for (Reference value in addedLiteral.values) {
+        for (Reference value in addedLiteral.valueRefs) {
           cps.invokeBuiltin(BuiltinMethod.Push,
               list,
               <Primitive>[value.definition]);
@@ -1678,8 +1709,8 @@
 
         CpsFragment cps = new CpsFragment(node.sourceInformation);
         Primitive result = cps.inlineFunction(target,
-            node.receiver.definition,
-            node.arguments.map((ref) => ref.definition).toList(),
+            node.receiver,
+            node.arguments.toList(),
             hint: node.hint);
         node.replaceUsesWith(result);
         return cps;
@@ -1697,7 +1728,7 @@
         for (Reference ref in iterator.refinedUses) {
           if (ref.parent is! InvokeMethod) return null;
           InvokeMethod use = ref.parent;
-          if (ref != use.receiver) return null;
+          if (ref != use.receiverRef) return null;
           if (use.selector != Selectors.moveNext &&
               use.selector != Selectors.current) {
             return null;
@@ -1865,7 +1896,7 @@
     if (!call.isClosureCall) return null;
 
     assert(!isInterceptedSelector(call));
-    assert(call.argumentCount == node.arguments.length);
+    assert(call.argumentCount == node.argumentRefs.length);
 
     Primitive tearOff = node.dartReceiver.effectiveDefinition;
     // Note: We don't know if [tearOff] is actually a tear-off.
@@ -1886,7 +1917,7 @@
       // The tear-off will be cleaned up by shrinking reductions.
       return new InvokeStatic(target,
           new Selector.fromElement(target),
-          node.arguments.map((ref) => ref.definition).toList(),
+          node.arguments.toList(),
           node.sourceInformation);
     }
     if (tearOff is InvokeMethod && tearOff.selector.isGetter) {
@@ -1897,7 +1928,7 @@
 
       LetPrim tearOffBinding = tearOff.parent;
 
-      Primitive object = tearOff.receiver.definition;
+      Primitive object = tearOff.receiver;
 
       // Ensure that the object actually has a foo member, since we might
       // otherwise alter a noSuchMethod call.
@@ -1932,9 +1963,9 @@
         object,
         new Selector.call(getter.memberName, call.callStructure),
         type,
-        node.arguments.map((ref) => ref.definition).toList(),
+        node.arguments.toList(),
         sourceInformation: node.sourceInformation);
-      node.receiver.changeTo(new Parameter(null)); // Remove the tear off use.
+      node.receiverRef.changeTo(new Parameter(null)); // Remove the tear off use.
 
       if (tearOff.hasNoRefinedUses) {
         // Eliminate the getter call if it has no more uses.
@@ -1962,9 +1993,9 @@
     if (!call.isClosureCall) return null;
 
     assert(!isInterceptedSelector(call));
-    assert(call.argumentCount == node.arguments.length);
+    assert(call.argumentCount == node.argumentRefs.length);
 
-    Primitive receiver = node.receiver.definition;
+    Primitive receiver = node.receiver;
     if (receiver is !CreateInstance) return null;
     CreateInstance createInstance = receiver;
     if (!createInstance.hasExactlyOneUse) return null;
@@ -2004,14 +2035,14 @@
       if (use is GetField) continue;
       // Closures do not currently have writable fields, but closure conversion
       // could esily be changed to allocate some cells in a closure object.
-      if (use is SetField && ref == use.object) continue;
+      if (use is SetField && ref == use.objectRef) continue;
       return null;
     }
 
     CpsFragment cps = new CpsFragment(node.sourceInformation);
     Primitive returnValue = cps.inlineFunction(target,
-        node.receiver.definition,
-        node.arguments.map((ref) => ref.definition).toList(),
+        node.receiver,
+        node.arguments.toList(),
         hint: node.hint);
     node.replaceUsesWith(returnValue);
     return cps;
@@ -2023,21 +2054,33 @@
     // might have to return JSNull.  That case is handled by visitInvokeMethod
     // and visitInvokeMethodDirectly which can sometimes tolerate that null
     // is used instead of JSNull.
-    Primitive input = node.input.definition;
+    Primitive input = node.input;
     if (!input.type.isNullable &&
         typeSystem.areDisjoint(input.type, typeSystem.interceptorType)) {
       node.replaceUsesWith(input);
     }
   }
 
+  visitInvokeConstructor(InvokeConstructor node) {
+    node.effects =
+        Effects.from(compiler.world.getSideEffectsOfElement(node.target));
+  }
+
   visitInvokeMethodDirectly(InvokeMethodDirectly node) {
+    Element target = node.target;
+    if (target is ConstructorBodyElement) {
+      ConstructorBodyElement constructorBody = target;
+      target = constructorBody.constructor;
+    }
+    node.effects =
+        Effects.from(compiler.world.getSideEffectsOfElement(target));
     TypeMask receiverType = node.dartReceiver.type;
     if (node.callingConvention == CallingConvention.Intercepted &&
         typeSystem.areDisjoint(receiverType, typeSystem.interceptorType)) {
       // Some direct calls take an interceptor because the target class is
       // mixed into a native class.  If it is known at the call site that the
       // receiver is non-intercepted, get rid of the interceptor.
-      node.receiver.changeTo(node.dartReceiver);
+      node.receiverRef.changeTo(node.dartReceiver);
     }
   }
 
@@ -2054,6 +2097,9 @@
     TypeMask receiverType = node.dartReceiver.type;
     node.mask = typeSystem.intersection(node.mask, receiverType);
 
+    node.effects = Effects.from(
+        compiler.world.getSideEffectsOfSelector(node.selector, node.mask));
+
     bool canBeNonThrowingCallOnNull =
         selectorsOnNull.contains(node.selector) &&
         receiverType.isNullable;
@@ -2063,7 +2109,7 @@
         typeSystem.areDisjoint(receiverType, typeSystem.interceptorType)) {
       // Use the Dart receiver as the JS receiver. This changes the wording of
       // the error message when the receiver is null, but we accept this.
-      node.receiver.changeTo(node.dartReceiver);
+      node.receiverRef.changeTo(node.dartReceiver);
 
       // Replace the extra receiver argument with a dummy value if the
       // target definitely does not use it.
@@ -2071,14 +2117,14 @@
             node.selector)) {
         Constant dummy = makeConstantPrimitive(new IntConstantValue(0));
         new LetPrim(dummy).insertAbove(node.parent);
-        node.arguments[0].changeTo(dummy);
+        node.argumentRefs[0].changeTo(dummy);
         node.callingConvention = CallingConvention.DummyIntercepted;
       }
     }
   }
 
   CpsFragment visitTypeCast(TypeCast node) {
-    AbstractConstantValue value = getValue(node.value.definition);
+    AbstractConstantValue value = getValue(node.value);
     switch (lattice.isSubtypeOf(value, node.dartType, allowNull: true)) {
       case AbstractBool.Maybe:
       case AbstractBool.Nothing:
@@ -2086,7 +2132,7 @@
 
       case AbstractBool.True:
         // Return an unused primitive moved again.
-        node.replaceUsesWith(node.value.definition);
+        node.replaceUsesWith(node.value);
         return new CpsFragment(); // Remove the node.
 
       case AbstractBool.False:
@@ -2099,7 +2145,7 @@
   /// Specialize calls to internal static methods.
   specializeInternalMethodCall(InvokeStatic node) {
     if (node.target == backend.helpers.stringInterpolationHelper) {
-      Primitive argument = node.arguments[0].definition;
+      Primitive argument = node.argument(0);
       AbstractConstantValue value = getValue(argument);
       if (lattice.isDefinitelyString(value)) {
         node.replaceUsesWith(argument);
@@ -2119,9 +2165,9 @@
         }
       }
     } else if (node.target == compiler.identicalFunction) {
-      if (node.arguments.length == 2) {
+      if (node.argumentRefs.length == 2) {
         return new ApplyBuiltinOperator(BuiltinOperator.Identical,
-            [node.arguments[0].definition, node.arguments[1].definition],
+            [node.argument(0), node.argument(1)],
             node.sourceInformation);
       }
     }
@@ -2129,6 +2175,8 @@
   }
 
   visitInvokeStatic(InvokeStatic node) {
+    node.effects = Effects.from(
+        compiler.world.getSideEffectsOfElement(node.target));
     return specializeInternalMethodCall(node);
   }
 
@@ -2165,13 +2213,11 @@
         // Concatenate consecutive constants.
         bool argumentsWereRemoved = false;
         int i = 0;
-        while (i < node.arguments.length - 1) {
+        while (i < node.argumentRefs.length - 1) {
           int startOfSequence = i;
-          AbstractConstantValue firstValue =
-              getValue(node.arguments[i++].definition);
+          AbstractConstantValue firstValue = getValue(node.argument(i++));
           if (!firstValue.isConstant) continue;
-          AbstractConstantValue secondValue =
-              getValue(node.arguments[i++].definition);
+          AbstractConstantValue secondValue = getValue(node.argument(i++));
           if (!secondValue.isConstant) continue;
 
           ast.DartString string =
@@ -2180,9 +2226,8 @@
 
           // We found a sequence of at least two constants.
           // Look for the end of the sequence.
-          while (i < node.arguments.length) {
-            AbstractConstantValue value =
-                getValue(node.arguments[i].definition);
+          while (i < node.argumentRefs.length) {
+            AbstractConstantValue value = getValue(node.argument(i));
             if (!value.isConstant) break;
             string = new ast.ConsDartString(string, getString(value));
             ++i;
@@ -2191,18 +2236,18 @@
               makeConstantPrimitive(new StringConstantValue(string));
           new LetPrim(prim).insertAbove(node.parent);
           for (int k = startOfSequence; k < i; ++k) {
-            node.arguments[k].unlink();
-            node.arguments[k] = null; // Remove the argument after the loop.
+            node.argumentRefs[k].unlink();
+            node.argumentRefs[k] = null; // Remove the argument after the loop.
           }
-          node.arguments[startOfSequence] = new Reference<Primitive>(prim);
-          node.arguments[startOfSequence].parent = node;
+          node.argumentRefs[startOfSequence] = new Reference<Primitive>(prim);
+          node.argumentRefs[startOfSequence].parent = node;
           argumentsWereRemoved = true;
         }
         if (argumentsWereRemoved) {
-          node.arguments.removeWhere((ref) => ref == null);
+          node.argumentRefs.removeWhere((ref) => ref == null);
         }
-        if (node.arguments.length == 1) {
-          Primitive input = node.arguments[0].definition;
+        if (node.argumentRefs.length == 1) {
+          Primitive input = node.argument(0);
           node.replaceUsesWith(input);
           input.useElementAsHint(node.hint);
         }
@@ -2211,8 +2256,8 @@
         break;
 
       case BuiltinOperator.Identical:
-        Primitive leftArg = node.arguments[0].definition;
-        Primitive rightArg = node.arguments[1].definition;
+        Primitive leftArg = node.argument(0);
+        Primitive rightArg = node.argument(1);
         AbstractConstantValue left = getValue(leftArg);
         AbstractConstantValue right = getValue(rightArg);
         BuiltinOperator newOperator;
@@ -2239,7 +2284,7 @@
         }
         if (newOperator != null) {
           return new ApplyBuiltinOperator(newOperator,
-              node.arguments.map((ref) => ref.definition).toList(),
+              node.arguments.toList(),
               node.sourceInformation);
         }
         break;
@@ -2253,8 +2298,8 @@
             node.operator == BuiltinOperator.LooseNeq;
         for (int firstIndex in [0, 1]) {
           int secondIndex = 1 - firstIndex;
-          Primitive firstArg = node.arguments[firstIndex].definition;
-          Primitive secondArg = node.arguments[secondIndex].definition;
+          Primitive firstArg = node.argument(firstIndex);
+          Primitive secondArg = node.argument(secondIndex);
           AbstractConstantValue first = getValue(firstArg);
           if (!lattice.isDefinitelyBool(first)) continue;
           AbstractConstantValue second = getValue(secondArg);
@@ -2285,7 +2330,7 @@
   }
 
   visitTypeTest(TypeTest node) {
-    Primitive prim = node.value.definition;
+    Primitive prim = node.value;
 
     Primitive unaryBuiltinOperator(BuiltinOperator operator) =>
         new ApplyBuiltinOperator(
@@ -2391,11 +2436,11 @@
     // The [BoundsChecker] pass does not try to eliminate checks that could be
     // eliminated by constant folding.
     if (node.hasNoChecks) return;
-    Primitive indexPrim = node.index.definition;
+    Primitive indexPrim = node.index;
     int index = lattice.intValue(getValue(indexPrim));
-    int length = node.length == null
+    int length = node.lengthRef == null
         ? null
-        : lattice.intValue(getValue(node.length.definition));
+        : lattice.intValue(getValue(node.length));
     if (index != null && length != null && index < length) {
       node.checks &= ~BoundsCheck.UPPER_BOUND;
     }
@@ -2408,8 +2453,8 @@
     if (typeSystem.isDefinitelyInt(indexPrim.type)) {
       node.checks &= ~BoundsCheck.INTEGER;
     }
-    if (!node.lengthUsedInCheck && node.length != null) {
-      node..length.unlink()..length = null;
+    if (!node.lengthUsedInCheck && node.lengthRef != null) {
+      node..lengthRef.unlink()..lengthRef = null;
     }
     if (node.checks == BoundsCheck.NONE) {
       // We can't remove the bounds check node because it may still be used to
@@ -2420,12 +2465,12 @@
       //     restrict code motion.  However, if we want to run this pass after
       //     [BoundsChecker] that would not be safe any more, so for now we
       //     keep the node for forward compatibilty.
-      node..index.unlink()..index = null;
+      node..indexRef.unlink()..indexRef = null;
     }
   }
 
   visitReceiverCheck(ReceiverCheck node) {
-    Primitive input = node.value.definition;
+    Primitive input = node.value;
     if (!input.type.isNullable &&
         (node.isNullCheck ||
          !input.type.needsNoSuchMethodHandling(node.selector, classWorld))) {
@@ -2435,6 +2480,11 @@
     return null;
   }
 
+  visitGetLength(GetLength node) {
+    node.isFinal = typeSystem.isDefinitelyFixedLengthIndexable(
+        node.object.type, allowNull: true);
+  }
+
   visitReadTypeVariable(ReadTypeVariable node) {
     // Pattern match on
     //
@@ -2449,11 +2499,11 @@
     // TODO(sra): A non-shrinking version of this rewrite could be done as part
     // of scalar replacement.
 
-    if (node.target.definition is CreateInstance) {
-      CreateInstance instance = node.target.definition;
-      if (instance.typeInformation != null &&
-          instance.typeInformation.definition is TypeExpression) {
-        TypeExpression typeExpression = instance.typeInformation.definition;
+    if (node.target is CreateInstance) {
+      CreateInstance instance = node.target;
+      if (instance.typeInformationRef != null &&
+          instance.typeInformation is TypeExpression) {
+        TypeExpression typeExpression = instance.typeInformation;
         assert(typeExpression.kind == TypeExpressionKind.INSTANCE);
         ClassElement context = node.variable.element.enclosingClass;
         // In the general case, a substitution could generate a large type
@@ -2463,8 +2513,8 @@
         if (!functionCompiler.glue.needsSubstitutionForTypeVariableAccess(
                 context)) {
           int index = functionCompiler.glue.getTypeVariableIndex(node.variable);
-          if (0 <= index && index < typeExpression.arguments.length) {
-            node.replaceUsesWith(typeExpression.arguments[index].definition);
+          if (0 <= index && index < typeExpression.argumentRefs.length) {
+            node.replaceUsesWith(typeExpression.argument(index));
             return new CpsFragment();
           }
         }
@@ -2696,13 +2746,13 @@
   }
 
   void visitLetMutable(LetMutable node) {
-    setValue(node.variable, getValue(node.value.definition));
+    setValue(node.variable, getValue(node.value));
     push(node.body);
   }
 
   void visitInvokeStatic(InvokeStatic node) {
     if (node.target == backend.helpers.stringInterpolationHelper) {
-      AbstractConstantValue argValue = getValue(node.arguments[0].definition);
+      AbstractConstantValue argValue = getValue(node.argument(0));
       setResult(node, lattice.stringify(argValue), canReplace: true);
       return;
     }
@@ -2712,13 +2762,13 @@
   }
 
   void visitInvokeContinuation(InvokeContinuation node) {
-    Continuation cont = node.continuation.definition;
+    Continuation cont = node.continuation;
     setReachable(cont);
 
     // Forward the constant status of all continuation invokes to the
     // continuation. Note that this is effectively a phi node in SSA terms.
-    for (int i = 0; i < node.arguments.length; i++) {
-      Primitive def = node.arguments[i].definition;
+    for (int i = 0; i < node.argumentRefs.length; i++) {
+      Primitive def = node.argument(i);
       AbstractConstantValue cell = getValue(def);
       setValue(cont.parameters[i], cell);
     }
@@ -2726,7 +2776,6 @@
 
   void visitInvokeMethod(InvokeMethod node) {
     AbstractConstantValue receiver = getValue(node.dartReceiver);
-    node.receiverIsNotNull = receiver.isDefinitelyNotNull;
     if (receiver.isNothing) {
       return setResult(node, lattice.nothing);
     }
@@ -2796,7 +2845,7 @@
     void unaryOp(
         AbstractConstantValue operation(AbstractConstantValue argument),
         TypeMask defaultType) {
-      AbstractConstantValue value = getValue(node.arguments[0].definition);
+      AbstractConstantValue value = getValue(node.argument(0));
       setValue(node, operation(value) ?? nonConstant(defaultType));
     }
 
@@ -2804,8 +2853,8 @@
         AbstractConstantValue operation(AbstractConstantValue left,
                                         AbstractConstantValue right),
         TypeMask defaultType) {
-      AbstractConstantValue left = getValue(node.arguments[0].definition);
-      AbstractConstantValue right = getValue(node.arguments[1].definition);
+      AbstractConstantValue left = getValue(node.argument(0));
+      AbstractConstantValue right = getValue(node.argument(1));
       setValue(node, operation(left, right) ?? nonConstant(defaultType));
     }
 
@@ -2830,7 +2879,7 @@
     switch (node.operator) {
       case BuiltinOperator.StringConcatenate:
         ast.DartString stringValue = const ast.LiteralDartString('');
-        for (Reference<Primitive> arg in node.arguments) {
+        for (Reference<Primitive> arg in node.argumentRefs) {
           AbstractConstantValue value = getValue(arg.definition);
           if (value.isNothing) {
             setValue(node, lattice.nothing);
@@ -2865,8 +2914,8 @@
         bool negated =
             node.operator == BuiltinOperator.StrictNeq ||
             node.operator == BuiltinOperator.LooseNeq;
-        AbstractConstantValue left = getValue(node.arguments[0].definition);
-        AbstractConstantValue right = getValue(node.arguments[1].definition);
+        AbstractConstantValue left = getValue(node.argument(0));
+        AbstractConstantValue right = getValue(node.argument(1));
         if (left.isNothing || right.isNothing) {
           setValue(node, lattice.nothing);
           return;
@@ -2980,7 +3029,7 @@
   }
 
   void visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
-    AbstractConstantValue receiver = getValue(node.receiver.definition);
+    AbstractConstantValue receiver = getValue(node.receiver);
     if (node.method == BuiltinMethod.Pop) {
       setValue(node, nonConstant(
           typeSystem.elementTypeOfIndexable(receiver.type)));
@@ -3017,7 +3066,7 @@
   }
 
   void visitBranch(Branch node) {
-    AbstractConstantValue conditionCell = getValue(node.condition.definition);
+    AbstractConstantValue conditionCell = getValue(node.condition);
     AbstractBool boolifiedValue = node.isStrictCheck
         ? lattice.strictBoolify(conditionCell)
         : lattice.boolify(conditionCell);
@@ -3025,20 +3074,20 @@
       case AbstractBool.Nothing:
         break;
       case AbstractBool.True:
-        setReachable(node.trueContinuation.definition);
+        setReachable(node.trueContinuation);
         break;
       case AbstractBool.False:
-        setReachable(node.falseContinuation.definition);
+        setReachable(node.falseContinuation);
         break;
       case AbstractBool.Maybe:
-        setReachable(node.trueContinuation.definition);
-        setReachable(node.falseContinuation.definition);
+        setReachable(node.trueContinuation);
+        setReachable(node.falseContinuation);
         break;
     }
   }
 
   void visitTypeTest(TypeTest node) {
-    handleTypeTest(node, getValue(node.value.definition), node.dartType);
+    handleTypeTest(node, getValue(node.value), node.dartType);
   }
 
   void visitTypeTestViaFlag(TypeTestViaFlag node) {
@@ -3071,7 +3120,7 @@
   }
 
   void visitTypeCast(TypeCast node) {
-    AbstractConstantValue input = getValue(node.value.definition);
+    AbstractConstantValue input = getValue(node.value);
     switch (lattice.isSubtypeOf(input, node.dartType, allowNull: true)) {
       case AbstractBool.Nothing:
         setValue(node, lattice.nothing);
@@ -3096,7 +3145,7 @@
   }
 
   void visitSetMutable(SetMutable node) {
-    setValue(node.variable.definition, getValue(node.value.definition));
+    setValue(node.variable, getValue(node.value));
   }
 
   void visitLiteralList(LiteralList node) {
@@ -3118,7 +3167,7 @@
   }
 
   void visitGetMutable(GetMutable node) {
-    setValue(node, getValue(node.variable.definition));
+    setValue(node, getValue(node.variable));
   }
 
   void visitMutableVariable(MutableVariable node) {
@@ -3150,8 +3199,8 @@
   }
 
   void visitInterceptor(Interceptor node) {
-    push(node.input.definition);
-    AbstractConstantValue value = getValue(node.input.definition);
+    push(node.input);
+    AbstractConstantValue value = getValue(node.input);
     if (value.isNothing) {
       setValue(node, nothing);
     } else if (value.isNullable &&
@@ -3167,7 +3216,7 @@
   }
 
   void visitGetField(GetField node) {
-    AbstractConstantValue object = getValue(node.object.definition);
+    AbstractConstantValue object = getValue(node.object);
     if (object.isNothing || object.isNullConstant) {
       setValue(node, nothing);
       return;
@@ -3220,8 +3269,8 @@
   @override
   void visitForeignCode(ForeignCode node) {
     bool firstArgumentIsNullable = false;
-    if (node.arguments.length > 0) {
-      AbstractConstantValue first = getValue(node.arguments.first.definition);
+    if (node.argumentRefs.length > 0) {
+      AbstractConstantValue first = getValue(node.argumentRefs.first.definition);
       if (first.isNothing) {
         setValue(node, nothing);
         return;
@@ -3238,7 +3287,7 @@
 
   @override
   void visitGetLength(GetLength node) {
-    AbstractConstantValue input = getValue(node.object.definition);
+    AbstractConstantValue input = getValue(node.object);
     node.objectIsNotNull = input.isDefinitelyNotNull;
     AbstractConstantValue length = lattice.lengthSpecial(input);
     if (length != null) {
@@ -3252,7 +3301,7 @@
 
   @override
   void visitGetIndex(GetIndex node) {
-    AbstractConstantValue object = getValue(node.object.definition);
+    AbstractConstantValue object = getValue(node.object);
     if (object.isNothing || object.isNullConstant) {
       setValue(node, nothing);
     } else {
@@ -3283,12 +3332,12 @@
 
   @override
   void visitBoundsCheck(BoundsCheck node) {
-    setValue(node, getValue(node.object.definition));
+    setValue(node, getValue(node.object));
   }
 
   @override
   void visitReceiverCheck(ReceiverCheck node) {
-    AbstractConstantValue value = getValue(node.value.definition);
+    AbstractConstantValue value = getValue(node.value);
     if (node.isNullCheck) {
       // Avoid expensive TypeMask operations for null checks.
       setValue(node, lattice.nonNullable(value));
diff --git a/pkg/compiler/lib/src/cps_ir/update_refinements.dart b/pkg/compiler/lib/src/cps_ir/update_refinements.dart
index 5ce47a2..313f2cb 100644
--- a/pkg/compiler/lib/src/cps_ir/update_refinements.dart
+++ b/pkg/compiler/lib/src/cps_ir/update_refinements.dart
@@ -37,9 +37,9 @@
   }
 
   visitReceiverCheck(ReceiverCheck node) {
-    if (refine(node.value)) {
+    if (refine(node.valueRef)) {
       // Update the type if the input has changed.
-      Primitive value = node.value.definition;
+      Primitive value = node.value;
       if (value.type.needsNoSuchMethodHandling(node.selector, classWorld)) {
         node.type = typeSystem.receiverTypeFor(node.selector, value.type);
       } else {
@@ -76,7 +76,7 @@
   visitBoundsCheck(BoundsCheck node) {
     super.visitBoundsCheck(node);
     if (node.hasIntegerCheck &&
-        typeSystem.isDefinitelyInt(node.index.definition.type)) {
+        typeSystem.isDefinitelyInt(node.index.type)) {
       node.checks &= ~BoundsCheck.INTEGER;
     }
   }
diff --git a/pkg/compiler/lib/src/cps_ir/use_field_initializers.dart b/pkg/compiler/lib/src/cps_ir/use_field_initializers.dart
index a8944c6..ca510f7 100644
--- a/pkg/compiler/lib/src/cps_ir/use_field_initializers.dart
+++ b/pkg/compiler/lib/src/cps_ir/use_field_initializers.dart
@@ -94,7 +94,7 @@
   }
 
   void visitLetMutable(LetMutable node) {
-    escape(node.value);
+    escape(node.valueRef);
   }
 
   void visitLetCont(LetCont node) {
@@ -125,24 +125,24 @@
     Primitive prim = node.primitive;
     if (prim is CreateInstance) {
       unescaped.add(prim);
-      prim.arguments.forEach(escape);
+      prim.argumentRefs.forEach(escape);
       return;
     }
     if (unescaped.isEmpty) return;
     if (prim is SetField) {
-      escape(prim.value);
-      Primitive object = prim.object.definition;
+      escape(prim.valueRef);
+      Primitive object = prim.object;
       if (object is CreateInstance && unescaped.contains(object)) {
         int index = getFieldIndex(object.classElement, prim.field);
         if (index == -1) {
           // This field is not initialized at creation time, so we cannot pull
           // set SetField into the CreateInstance instruction.  We have to
           // leave the instruction here, and this counts as a use of the object.
-          escape(prim.object);
+          escape(prim.objectRef);
         } else {
           // Replace the field initializer with the new value. There are no uses
           // of the object before this, so the old value cannot have been seen.
-          object.arguments[index].changeTo(prim.value.definition);
+          object.argumentRefs[index].changeTo(prim.value);
           prim.destroy();
           // The right-hand side might not be in scope at the CreateInstance.
           // Sink the creation down to this point.
@@ -156,13 +156,13 @@
       // When reading the field of a newly created object, just use the initial
       // value and destroy the GetField. This can unblock the other optimization
       // since we remove a use of the object.
-      Primitive object = prim.object.definition;
+      Primitive object = prim.object;
       if (object is CreateInstance && unescaped.contains(object)) {
         int index = getFieldIndex(object.classElement, prim.field);
         if (index == -1) {
-          escape(prim.object);
+          escape(prim.objectRef);
         } else {
-          prim.replaceUsesWith(object.arguments[index].definition);
+          prim.replaceUsesWith(object.argument(index));
           prim.destroy();
           node.remove();
         }
diff --git a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
index 1d2549d..4d0f497 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
@@ -1211,20 +1211,20 @@
     return js.js('# >>> 0', [op]);
   }
 
-
-  /// The JS name of a built-in method.
-  static final Map<BuiltinMethod, String> builtinMethodName =
-    const <BuiltinMethod, String>{
-      BuiltinMethod.Push: 'push',
-      BuiltinMethod.Pop: 'pop',
-  };
-
   @override
   js.Expression visitApplyBuiltinMethod(tree_ir.ApplyBuiltinMethod node) {
-    String name = builtinMethodName[node.method];
     js.Expression receiver = visitExpression(node.receiver);
     List<js.Expression> args = visitExpressionList(node.arguments);
-    return js.js('#.#(#)', [receiver, name, args]);
+    switch (node.method) {
+      case BuiltinMethod.Push:
+        return js.js('#.push(#)', [receiver, args]);
+
+      case BuiltinMethod.Pop:
+        return js.js('#.pop()', [receiver]);
+
+      case BuiltinMethod.SetLength:
+        return js.js('#.length = #', [receiver, args[0]]);
+    }
   }
 
   @override
diff --git a/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart b/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart
index 2596b91..4ca64fa 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart
@@ -150,7 +150,7 @@
 
       // Replace the dummy with the exception parameter.  It must be set after
       // replacing all uses of [_exceptionParameter].
-      unwrapped.arguments[0].changeTo(_exceptionParameter);
+      unwrapped.argumentRefs[0].changeTo(_exceptionParameter);
 
       if (stackTraceParameter.hasAtLeastOneUse) {
         InvokeStatic stackTraceValue = insertStaticCallAbove(
@@ -174,9 +174,9 @@
     // The subexpression of throw is wrapped in the JavaScript output.
     Primitive wrappedException = insertStaticCallAbove(
         _glue.getWrapExceptionHelper(),
-        [node.value.definition],
+        [node.value],
         node);
-    node.value.changeTo(wrappedException);
+    node.valueRef.changeTo(wrappedException);
   }
 
   processRethrow(Rethrow node) {
@@ -201,16 +201,16 @@
     // Some platform libraries will compare non-interceptable objects against
     // null using the Dart == operator.  These must be translated directly.
     if (node.selector == Selectors.equals &&
-        node.arguments.length == 1 &&
-        isNullConstant(node.arguments[0].definition)) {
+        node.argumentRefs.length == 1 &&
+        isNullConstant(node.argument(0))) {
       node.replaceWith(new ApplyBuiltinOperator(
           BuiltinOperator.Identical,
-          [node.receiver.definition, node.arguments[0].definition],
+          [node.receiver, node.argument(0)],
           node.sourceInformation));
       return;
     }
 
-    Primitive receiver = node.receiver.definition;
+    Primitive receiver = node.receiver;
     Primitive newReceiver;
 
     if (receiver == explicitReceiverParameter) {
@@ -225,15 +225,15 @@
       }
       new LetPrim(newReceiver).insertAbove(node.parent);
     }
-    node.arguments.insert(0, node.receiver);
-    node.receiver = new Reference<Primitive>(newReceiver)..parent = node;
+    node.argumentRefs.insert(0, node.receiverRef);
+    node.receiverRef = new Reference<Primitive>(newReceiver)..parent = node;
     node.callingConvention = CallingConvention.Intercepted;
   }
 
   processInvokeMethodDirectly(InvokeMethodDirectly node) {
     if (!_glue.isInterceptedMethod(node.target)) return;
 
-    Primitive receiver = node.receiver.definition;
+    Primitive receiver = node.receiver;
     Primitive newReceiver;
 
     if (receiver == explicitReceiverParameter) {
@@ -248,8 +248,8 @@
       }
       new LetPrim(newReceiver).insertAbove(node.parent);
     }
-    node.arguments.insert(0, node.receiver);
-    node.receiver = new Reference<Primitive>(newReceiver)..parent = node;
+    node.argumentRefs.insert(0, node.receiverRef);
+    node.receiverRef = new Reference<Primitive>(newReceiver)..parent = node;
     node.callingConvention = CallingConvention.Intercepted;
   }
 }
diff --git a/pkg/compiler/lib/src/serialization/element_serialization.dart b/pkg/compiler/lib/src/serialization/element_serialization.dart
index 6e7f5d4..173dd1e 100644
--- a/pkg/compiler/lib/src/serialization/element_serialization.dart
+++ b/pkg/compiler/lib/src/serialization/element_serialization.dart
@@ -381,7 +381,6 @@
     encoder.setElement(Key.TYPE_DECLARATION, element.typeDeclaration);
     encoder.setString(Key.NAME, element.name);
     SerializerUtil.serializePosition(element, encoder);
-    TypeDeclarationElement typeDeclaration = element.typeDeclaration;
     encoder.setType(Key.TYPE, element.type);
     encoder.setInt(Key.INDEX, element.index);
     encoder.setType(Key.BOUND, element.bound);
diff --git a/pkg/compiler/lib/src/serialization/modelz.dart b/pkg/compiler/lib/src/serialization/modelz.dart
index c31ee4a..23153bf 100644
--- a/pkg/compiler/lib/src/serialization/modelz.dart
+++ b/pkg/compiler/lib/src/serialization/modelz.dart
@@ -12,8 +12,6 @@
 import '../common.dart';
 import '../common/resolution.dart' show
     Resolution;
-import '../compiler.dart'
-    show Compiler;
 import '../constants/constructors.dart';
 import '../constants/expressions.dart';
 import '../core_types.dart';
@@ -96,9 +94,6 @@
   String get fixedBackendName => _unsupported('fixedBackendName');
 
   @override
-  bool get hasFixedBackendName => _unsupported('hasFixedBackendName');
-
-  @override
   LibraryElement get implementationLibrary => library;
 
   @override
@@ -132,15 +127,6 @@
   bool get isMixinApplication => false;
 
   @override
-  bool get isNative => false;
-
-  @override
-  bool get isJsInterop => false;
-
-  @override
-  String get jsInteropName => null;
-
-  @override
   bool get isOperator => false;
 
   @override
@@ -375,7 +361,6 @@
   List<ExportElement> _exports;
   ListedContainer _exportsMap;
   ListedContainer _importsMap;
-  Map<LibraryTag, LibraryElement> _libraryDependencies;
 
   LibraryElementZ(ObjectDecoder decoder)
       : super(decoder);
@@ -463,9 +448,6 @@
   }
 
   @override
-  bool get canUseNative => false;
-
-  @override
   Element findExported(String elementName) => _unsupported('findExported');
 
   void _ensureImports() {
@@ -893,9 +875,6 @@
   }
 
   @override
-  String get nativeTagInfo => _unsupported('nativeTagInfo');
-
-  @override
   void reverseBackendMembers() => _unsupported('reverseBackendMembers');
 
   @override
diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
index a9c2831..324f45f 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
@@ -396,7 +396,7 @@
 
   NodeCallback visitLetMutable(cps_ir.LetMutable node) {
     Variable variable = addMutableVariable(node.variable);
-    Expression value = getVariableUse(node.value);
+    Expression value = getVariableUse(node.valueRef);
     return (Statement next) => Assign.makeStatement(variable, value, next);
   }
 
@@ -406,7 +406,7 @@
   // (not a function like interior and call expressions).
 
   Statement visitThrow(cps_ir.Throw node) {
-    Expression value = getVariableUse(node.value);
+    Expression value = getVariableUse(node.valueRef);
     return new Throw(value);
   }
 
@@ -420,13 +420,13 @@
     // arguments to formal parameter variables, followed by the body if
     // the continuation is singly reference or a break if it is multiply
     // referenced.
-    cps_ir.Continuation cont = node.continuation.definition;
+    cps_ir.Continuation cont = node.continuation;
     if (cont == returnContinuation) {
-      assert(node.arguments.length == 1);
-      return new Return(getVariableUse(node.arguments.single),
+      assert(node.argumentRefs.length == 1);
+      return new Return(getVariableUse(node.argumentRefs.single),
                         sourceInformation: node.sourceInformation);
     } else {
-      List<Expression> arguments = translateArguments(node.arguments);
+      List<Expression> arguments = translateArguments(node.argumentRefs);
       return buildPhiAssignments(cont.parameters, arguments,
           () {
             // Translate invocations of recursive and non-recursive
@@ -456,7 +456,7 @@
 
   /// Translates a branch condition to a tree expression.
   Expression translateCondition(cps_ir.Branch branch) {
-    Expression value = getVariableUse(branch.condition);
+    Expression value = getVariableUse(branch.conditionRef);
     if (branch.isStrictCheck) {
       return new ApplyBuiltinOperator(
           BuiltinOperator.StrictEq,
@@ -469,12 +469,12 @@
   Statement visitBranch(cps_ir.Branch node) {
     Expression condition = translateCondition(node);
     Statement thenStatement, elseStatement;
-    cps_ir.Continuation cont = node.trueContinuation.definition;
+    cps_ir.Continuation cont = node.trueContinuation;
     assert(cont.parameters.isEmpty);
     thenStatement = cont.hasExactlyOneUse
         ? translateExpression(cont.body)
         : new Break(labels[cont]);
-    cont = node.falseContinuation.definition;
+    cont = node.falseContinuation;
     assert(cont.parameters.isEmpty);
     elseStatement = cont.hasExactlyOneUse
         ? translateExpression(cont.body)
@@ -489,13 +489,13 @@
   //
 
   Expression visitSetField(cps_ir.SetField node) {
-    return new SetField(getVariableUse(node.object),
+    return new SetField(getVariableUse(node.objectRef),
                         node.field,
-                        getVariableUse(node.value));
+                        getVariableUse(node.valueRef));
   }
 
   Expression visitInterceptor(cps_ir.Interceptor node) {
-    return new Interceptor(getVariableUse(node.input),
+    return new Interceptor(getVariableUse(node.inputRef),
                            node.interceptedClasses,
                            node.sourceInformation);
   }
@@ -503,14 +503,14 @@
   Expression visitCreateInstance(cps_ir.CreateInstance node) {
     return new CreateInstance(
         node.classElement,
-        translateArguments(node.arguments),
-        getVariableUseOrNull(node.typeInformation),
+        translateArguments(node.argumentRefs),
+        getVariableUseOrNull(node.typeInformationRef),
         node.sourceInformation);
   }
 
   Expression visitGetField(cps_ir.GetField node) {
-    return new GetField(getVariableUse(node.object), node.field,
-        objectIsNotNull: !node.object.definition.type.isNullable);
+    return new GetField(getVariableUse(node.objectRef), node.field,
+        objectIsNotNull: !node.object.type.isNullable);
   }
 
   Expression visitCreateBox(cps_ir.CreateBox node) {
@@ -520,16 +520,16 @@
   Expression visitCreateInvocationMirror(cps_ir.CreateInvocationMirror node) {
     return new CreateInvocationMirror(
         node.selector,
-        translateArguments(node.arguments));
+        translateArguments(node.argumentRefs));
   }
 
   Expression visitGetMutable(cps_ir.GetMutable node) {
-    return getMutableVariableUse(node.variable);
+    return getMutableVariableUse(node.variableRef);
   }
 
   Expression visitSetMutable(cps_ir.SetMutable node) {
-    Variable variable = getMutableVariable(node.variable.definition);
-    Expression value = getVariableUse(node.value);
+    Variable variable = getMutableVariable(node.variable);
+    Expression value = getVariableUse(node.valueRef);
     return new Assign(variable, value);
   }
 
@@ -540,18 +540,18 @@
   Expression visitLiteralList(cps_ir.LiteralList node) {
     return new LiteralList(
             node.dartType,
-            translateArguments(node.values));
+            translateArguments(node.valueRefs));
   }
 
   Expression visitReifyRuntimeType(cps_ir.ReifyRuntimeType node) {
     return new ReifyRuntimeType(
-        getVariableUse(node.value), node.sourceInformation);
+        getVariableUse(node.valueRef), node.sourceInformation);
   }
 
   Expression visitReadTypeVariable(cps_ir.ReadTypeVariable node) {
     return new ReadTypeVariable(
         node.variable,
-        getVariableUse(node.target),
+        getVariableUse(node.targetRef),
         node.sourceInformation);
   }
 
@@ -559,17 +559,17 @@
     return new TypeExpression(
         node.kind,
         node.dartType,
-        node.arguments.map(getVariableUse).toList());
+        node.argumentRefs.map(getVariableUse).toList());
   }
 
   Expression visitTypeTest(cps_ir.TypeTest node) {
-    Expression value = getVariableUse(node.value);
-    List<Expression> typeArgs = translateArguments(node.typeArguments);
+    Expression value = getVariableUse(node.valueRef);
+    List<Expression> typeArgs = translateArguments(node.typeArgumentRefs);
     return new TypeOperator(value, node.dartType, typeArgs, isTypeTest: true);
   }
 
   Expression visitTypeTestViaFlag(cps_ir.TypeTestViaFlag node) {
-    Expression value = getVariableUse(node.interceptor);
+    Expression value = getVariableUse(node.interceptorRef);
     // TODO(sra): Move !! to cps_ir level.
     return new Not(new Not(new GetTypeTestProperty(value, node.dartType)));
   }
@@ -581,42 +581,42 @@
   Expression visitSetStatic(cps_ir.SetStatic node) {
     return new SetStatic(
         node.element,
-        getVariableUse(node.value),
+        getVariableUse(node.valueRef),
         node.sourceInformation);
   }
 
   Expression visitApplyBuiltinOperator(cps_ir.ApplyBuiltinOperator node) {
     if (node.operator == BuiltinOperator.IsFalsy) {
-      return new Not(getVariableUse(node.arguments.single));
+      return new Not(getVariableUse(node.argumentRefs.single));
     }
     return new ApplyBuiltinOperator(node.operator,
-                                    translateArguments(node.arguments));
+                                    translateArguments(node.argumentRefs));
   }
 
   Expression visitApplyBuiltinMethod(cps_ir.ApplyBuiltinMethod node) {
     return new ApplyBuiltinMethod(node.method,
-        getVariableUse(node.receiver),
-        translateArguments(node.arguments),
-        receiverIsNotNull: !node.receiver.definition.type.isNullable);
+        getVariableUse(node.receiverRef),
+        translateArguments(node.argumentRefs),
+        receiverIsNotNull: !node.receiver.type.isNullable);
   }
 
   Expression visitGetLength(cps_ir.GetLength node) {
-    return new GetLength(getVariableUse(node.object));
+    return new GetLength(getVariableUse(node.objectRef));
   }
 
   Expression visitGetIndex(cps_ir.GetIndex node) {
-    return new GetIndex(getVariableUse(node.object),
-                        getVariableUse(node.index));
+    return new GetIndex(getVariableUse(node.objectRef),
+                        getVariableUse(node.indexRef));
   }
 
   Expression visitSetIndex(cps_ir.SetIndex node) {
-    return new SetIndex(getVariableUse(node.object),
-                        getVariableUse(node.index),
-                        getVariableUse(node.value));
+    return new SetIndex(getVariableUse(node.objectRef),
+                        getVariableUse(node.indexRef),
+                        getVariableUse(node.valueRef));
   }
 
   Expression visitInvokeStatic(cps_ir.InvokeStatic node) {
-    List<Expression> arguments = translateArguments(node.arguments);
+    List<Expression> arguments = translateArguments(node.argumentRefs);
     return new InvokeStatic(node.target, node.selector, arguments,
                                          node.sourceInformation);
   }
@@ -624,17 +624,17 @@
   Expression visitInvokeMethod(cps_ir.InvokeMethod node) {
     if (node.callingConvention == cps_ir.CallingConvention.OneShotIntercepted) {
       List<Expression> arguments = new List.generate(
-          1 + node.arguments.length,
-          (n) => getVariableUse(n == 0 ? node.receiver : node.arguments[n - 1]),
+          1 + node.argumentRefs.length,
+          (n) => getVariableUse(n == 0 ? node.receiverRef : node.argumentRefs[n - 1]),
           growable: false);
       return new OneShotInterceptor(node.selector, node.mask, arguments,
           node.sourceInformation);
     }
     InvokeMethod invoke = new InvokeMethod(
-        getVariableUse(node.receiver),
+        getVariableUse(node.receiverRef),
         node.selector,
         node.mask,
-        translateArguments(node.arguments),
+        translateArguments(node.argumentRefs),
         node.sourceInformation);
     // Sometimes we know the Dart receiver is non-null because it has been
     // refined, which implies that the JS receiver also can not be null at the
@@ -644,25 +644,25 @@
     // interceptor is non-null because it intercepts JSNull.
     invoke.receiverIsNotNull =
         !node.dartReceiver.type.isNullable ||
-        !node.receiver.definition.type.isNullable;
+        !node.receiver.type.isNullable;
     return invoke;
   }
 
   Expression visitInvokeMethodDirectly(cps_ir.InvokeMethodDirectly node) {
-    Expression receiver = getVariableUse(node.receiver);
-    List<Expression> arguments = translateArguments(node.arguments);
+    Expression receiver = getVariableUse(node.receiverRef);
+    List<Expression> arguments = translateArguments(node.argumentRefs);
     return new InvokeMethodDirectly(receiver, node.target,
         node.selector, arguments, node.sourceInformation);
   }
 
   Expression visitTypeCast(cps_ir.TypeCast node) {
-    Expression value = getVariableUse(node.value);
-    List<Expression> typeArgs = translateArguments(node.typeArguments);
+    Expression value = getVariableUse(node.valueRef);
+    List<Expression> typeArgs = translateArguments(node.typeArgumentRefs);
     return new TypeOperator(value, node.dartType, typeArgs, isTypeTest: false);
   }
 
   Expression visitInvokeConstructor(cps_ir.InvokeConstructor node) {
-    List<Expression> arguments = translateArguments(node.arguments);
+    List<Expression> arguments = translateArguments(node.argumentRefs);
     return new InvokeConstructor(
         node.dartType,
         node.target,
@@ -673,8 +673,8 @@
 
   visitForeignCode(cps_ir.ForeignCode node) {
     List<Expression> arguments =
-        node.arguments.map(getVariableUse).toList(growable: false);
-    List<bool> nullableArguments = node.arguments
+        node.argumentRefs.map(getVariableUse).toList(growable: false);
+    List<bool> nullableArguments = node.argumentRefs
         .map((argument) => argument.definition.type.isNullable)
         .toList(growable: false);
     if (node.codeTemplate.isExpression) {
@@ -704,8 +704,8 @@
     // In the Tree IR, syntax is more important, so the receiver check uses
     // "useInvoke" to denote if an invocation should be emitted.
     return new ReceiverCheck(
-        condition: getVariableUseOrNull(node.condition),
-        value: getVariableUse(node.value),
+        condition: getVariableUseOrNull(node.conditionRef),
+        value: getVariableUse(node.valueRef),
         selector: node.selector,
         useSelector: node.useSelector,
         useInvoke: !node.isNullCheck,
@@ -720,13 +720,13 @@
   @override
   NodeCallback visitYield(cps_ir.Yield node) {
     return (Statement next) {
-      return new Yield(getVariableUse(node.input), node.hasStar, next);
+      return new Yield(getVariableUse(node.inputRef), node.hasStar, next);
     };
   }
 
   @override
   Expression visitAwait(cps_ir.Await node) {
-    return new Await(getVariableUse(node.input));
+    return new Await(getVariableUse(node.inputRef));
   }
 
   @override
diff --git a/pkg/compiler/samples/jsonify/jsonify.dart b/pkg/compiler/samples/jsonify/jsonify.dart
index 152f39e..6e1e728 100644
--- a/pkg/compiler/samples/jsonify/jsonify.dart
+++ b/pkg/compiler/samples/jsonify/jsonify.dart
@@ -17,7 +17,6 @@
     show BackDoor;
 
 import '../../lib/src/filenames.dart';
-import '../../lib/src/io/source_file.dart';
 import '../../lib/src/source_file_provider.dart';
 import '../../lib/src/util/uri_extras.dart';
 
diff --git a/pkg/meta/CHANGELOG.md b/pkg/meta/CHANGELOG.md
index 6c3009b..fc3f06e 100644
--- a/pkg/meta/CHANGELOG.md
+++ b/pkg/meta/CHANGELOG.md
@@ -1,3 +1,7 @@
 ## 0.9.0
-* Introduce `@protected` annotation for methods that must only be called from
-instance methods of subclasses.
+* Introduce `@protected` annotation for members that must only be called from
+instance members of subclasses.
+* Introduce `@required` annotation for optional parameters that should be treated
+as required.
+* Introduce `@mustCallSuper` annotation for methods that must be invoked by all
+overriding methods.
diff --git a/pkg/meta/lib/meta.dart b/pkg/meta/lib/meta.dart
index a914ff6..c94fd80 100644
--- a/pkg/meta/lib/meta.dart
+++ b/pkg/meta/lib/meta.dart
@@ -18,17 +18,90 @@
 /// in the language tour.
 library meta;
 
-/// Used to annotate an instance method `m` in a class `C`. Indicates that `m`
-/// should only be invoked from instance methods of `C` or classes that extend
-/// or mix in `C`, either directly or indirectly. Additionally indicates that
-/// `m` should only be invoked on `this`, whether explicitly or implicitly.
+/// Used to annotate an instance method `m`. Indicates that `m` must either be
+/// abstract or must return a newly allocated object. In addition, every method
+/// that either implements or overrides `m` is implicitly annotated with this
+/// same annotation.
 ///
-/// Tools, such as the analyzer, can provide feedback if an invocation of a
-/// method marked as being protected is used outside of an instance method
-/// defined on a class that extends or mixes in the class in which the protected
-/// method is defined, or that uses a receiver other than `this`.
+/// Tools, such as the analyzer, can provide feedback if
+/// * the annotation is associated with anything other than an instance method,
+///   or
+/// * a method that has this annotation that can return anything other than a
+///   newly allocated object.
+const _Factory factory = const _Factory();
+
+/// Used to annotate a const constructor `c`. Indicates that any invocation of
+/// the constructor must use the keyword `const` unless one or more of the
+/// arguments to the constructor is not a compile-time constant.
+///
+/// Tools, such as the analyzer, can provide feedback if
+/// * the annotation is associated with anything other than a const constructor,
+///   or
+/// * an invocation of a constructor that has this annotation is not invoked
+///   using the `const` keyword unless one or more of the arguments to the
+///   constructor is not a compile-time constant.
+const _Literal literal = const _Literal();
+
+/// Used to annotate an instance method `m`. Indicates that every invocation of
+/// a method that overrides `m` must also invoke `m`. In addition, every method
+/// that overrides `m` is implicitly annotated with this same annotation.
+///
+/// Note that private methods with this annotation cannot be validly overridden
+/// outside of the library that defines the annotated method.
+///
+/// Tools, such as the analyzer, can provide feedback if
+/// * the annotation is associated with anything other than an instance method,
+///   or
+/// * a method that overrides a method that has this annotation can return
+///   without invoking the overridden method.
+const _MustCallSuper mustCallSuper = const _MustCallSuper();
+
+/// Used to annotate an instance member (method, getter, setter, operator, or
+/// field) `m` in a class `C`. If the annotation is on a field it applies to the
+/// getter, and setter if appropriate, that are induced by the field. Indicates
+/// that `m` should only be invoked from instance methods of `C` or classes that
+/// extend or mix in `C`, either directly or indirectly. Additionally indicates
+/// that `m` should only be invoked on `this`, whether explicitly or implicitly.
+///
+/// Tools, such as the analyzer, can provide feedback if
+/// * the annotation is associated with anything other than an instance member,
+///   or
+/// * an invocation of a member that has this annotation is used outside of an
+///   instance member defined on a class that extends or mixes in the class in
+///   which the protected member is defined, or that uses a receiver other than
+///   `this`.
 const _Protected protected = const _Protected();
 
+/// Used to annotate a named parameter `p` in a method or function `f`.
+/// Indicates that every invocation of `f` must include an argument
+/// corresponding to `p`, despite the fact that `p` would otherwise be an
+/// optional parameter.
+///
+/// Tools, such as the analyzer, can provide feedback if
+/// * the annotation is associated with anything other than a named parameter,
+/// * the annotation is associated with a named parameter in a method `m1` that
+///   overrides a method `m0` and `m0` defines a named parameter with the same
+///   name that does not have this annotation, or
+/// * an invocation of a method or function does not include an argument
+///   corresponding to a named parameter that has this annotation.
+const _Required required = const _Required();
+
+class _Factory {
+  const _Factory();
+}
+
+class _Literal {
+  const _Literal();
+}
+
+class _MustCallSuper {
+  const _MustCallSuper();
+}
+
 class _Protected {
   const _Protected();
 }
+
+class _Required {
+  const _Required();
+}
diff --git a/pkg/pkg.status b/pkg/pkg.status
index ef18a9b..f0e031c 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -53,9 +53,10 @@
 analyzer/test/generated/ast_test: Pass, Slow # Issue 21628
 analyzer/test/generated/compile_time_error_code_test: Pass, Slow
 analyzer/test/generated/compile_time_error_code_test: Pass, Slow # Issue 21628
-analyzer/test/generated/constant_test.dart: Pass, Slow # Issue 24914
+analyzer/test/generated/constant_test: Pass, Slow # Issue 24914
 analyzer/test/generated/declaration_resolver_test: Pass, Slow # Issue 24914
 analyzer/test/generated/element_test: Pass, Slow # Issue 21628
+analyzer/test/generated/error_suppression_test: Pass, Slow # Issue 21628
 analyzer/test/generated/engine_test: SkipSlow
 analyzer/test/generated/incremental_resolver_test: Pass, Slow # Issue 21628
 analyzer/test/generated/incremental_scanner_test: Pass, Slow # Issue 21628
@@ -92,6 +93,8 @@
 analyzer/test/src/task/options_test: Pass, Slow # Issue 21628
 analyzer/test/src/task/options_work_manager_test: Pass, Slow # Issue 21628
 analyzer/test/src/task/strong/checker_test: Pass, Slow # Issue 21628
+analyzer/test/src/task/strong/inferred_type_test: Pass, Slow # Issue 21628
+analyzer/test/src/task/yaml_test: Pass, Slow # Issue 21628
 collection/test/equality_test/01: Fail # Issue 1533
 collection/test/equality_test/02: Fail # Issue 1533
 collection/test/equality_test/03: Fail # Issue 1533
@@ -214,3 +217,6 @@
 analyzer/test/src/task/strong/checker_test: Crash # t: Failed assertion: line 88 pos 12: '!variable2index.containsKey(element)' is not true.
 analyzer/test/src/task/strong/inferred_type_test: Crash # t: Failed assertion: line 88 pos 12: '!variable2index.containsKey(element)' is not true.
 analyzer/test/src/task/strong_mode_test: Crash # Issue 24485
+
+[ $noopt || $runtime == dart_precompiled || $runtime == dart_product ]
+*: SkipByDesign # The pkg test framework imports dart:mirrors.
diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn
index 6932f93..62b69fb 100644
--- a/runtime/BUILD.gn
+++ b/runtime/BUILD.gn
@@ -87,6 +87,65 @@
   }
 }
 
+config("dart_config_no_precompiler") {
+  defines = []
+
+  if (dart_target_arch != "") {
+    if (dart_target_arch == "arm") {
+      defines += [ "TARGET_ARCH_ARM" ]
+    } else if (dart_target_arch == "arm64") {
+      defines += [ "TARGET_ARCH_ARM64" ]
+    } else if (dart_target_arch == "mips") {
+      defines += [ "TARGET_ARCH_MIPS" ]
+    } else if (dart_target_arch == "x64") {
+      defines += [ "TARGET_ARCH_X64" ]
+    } else if (dart_target_arch == "ia32") {
+      defines += [ "TARGET_ARCH_IA32" ]
+    } else  {
+      print("Invalid |dart_target_arch|")
+      assert(false)
+    }
+  }
+
+  if (dart_debug) {
+    defines += ["DEBUG"]
+  } else {
+    defines += ["NDEBUG"]
+  }
+
+  cflags = [
+    "-Werror",
+    "-Wall",
+    "-Wextra", # Also known as -W.
+    "-Wno-unused-parameter",
+    "-Wnon-virtual-dtor",
+    "-Wvla",
+    "-Wno-conversion-null",
+    "-Woverloaded-virtual",
+    "-g3",
+    "-ggdb3",
+    "-fno-rtti",
+    "-fno-exceptions",
+  ]
+
+  if (dart_debug) {
+    cflags += [
+      "-O1",
+    ]
+  } else {
+    cflags += [
+      "-O3",
+    ]
+  }
+
+  if (is_asan) {
+    ldflags = [
+      "-Wl,-u_sanitizer_options_link_helper",
+      "-fsanitize=address",
+    ]
+  }
+}
+
 
 static_library("libdart") {
   configs += [":dart_config"]
@@ -119,6 +178,38 @@
 }
 
 
+static_library("libdart_precompiled_runtime") {
+  configs += [":dart_config_no_precompiler"]
+  deps = [
+    "vm:libdart_lib_precompiled_runtime",
+    "vm:libdart_vm_precompiled_runtime",
+    "third_party/double-conversion/src:libdouble_conversion",
+    ":generate_version_cc_file",
+  ]
+  include_dirs = [
+    ".",
+  ]
+  public_configs = [":dart_public_config"]
+  sources = [
+    "include/dart_api.h",
+    "include/dart_mirrors_api.h",
+    "include/dart_native_api.h",
+    "include/dart_tools_api.h",
+    "vm/dart_api_impl.cc",
+    "vm/debugger_api_impl.cc",
+    "vm/mirrors_api_impl.cc",
+    "vm/native_api_impl.cc",
+    "vm/version.h",
+    "$target_gen_dir/version.cc",
+  ]
+  defines = [
+    # Using DART_SHARED_LIB to export the Dart API entries.
+    "DART_SHARED_LIB",
+    "DART_PRECOMPILED_RUNTIME",
+  ]
+}
+
+
 action("generate_version_cc_file") {
   deps = [
     ":libdart_dependency_helper",
diff --git a/runtime/bin/BUILD.gn b/runtime/bin/BUILD.gn
index 197eb32..02ba3c4 100644
--- a/runtime/bin/BUILD.gn
+++ b/runtime/bin/BUILD.gn
@@ -238,6 +238,7 @@
   custom_sources_filter = [
     "*net/nss_memio.cc",
     "*net/nss_memio.h",
+    "*root_certificates.cc",
     "*secure_socket.cc",
     "*secure_socket.h",
     "filter.cc",
@@ -292,6 +293,7 @@
   custom_sources_filter = [
     "*net/nss_memio.cc",
     "*net/nss_memio.h",
+    "*root_certificates.cc",
     "*secure_socket.cc",
     "*secure_socket.h",
     "*filter_unsupported.cc",
diff --git a/runtime/bin/gen_snapshot.cc b/runtime/bin/gen_snapshot.cc
index f1f7e2c..ea9f3d7 100644
--- a/runtime/bin/gen_snapshot.cc
+++ b/runtime/bin/gen_snapshot.cc
@@ -1014,7 +1014,10 @@
   TimerUtils::InitOnce();
   EventHandler::Start();
 
+#if !defined(PRODUCT)
+  // Constant true in PRODUCT mode.
   vm_options.AddArgument("--load_deferred_eagerly");
+#endif
 
   if (IsSnapshottingForPrecompilation()) {
     vm_options.AddArgument("--precompilation");
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index 4642486..bb21b9f 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -340,7 +340,10 @@
     precompiled_snapshot_directory = arg;
   }
   gen_precompiled_snapshot = true;
+#if !defined(DART_PRECOMPILED_RUNTIME)
+  // The precompiled runtime has FLAG_precompilation set as const.
   vm_options->AddArgument("--precompilation");
+#endif
   return true;
 }
 
@@ -355,7 +358,10 @@
     precompiled_snapshot_directory = &precompiled_snapshot_directory[1];
   }
   run_precompiled_snapshot = true;
+#if !defined(DART_PRECOMPILED_RUNTIME)
+  // The precompiled runtime has FLAG_precompilation set as const.
   vm_options->AddArgument("--precompilation");
+#endif
   return true;
 }
 
@@ -1556,11 +1562,14 @@
     Platform::Exit(kErrorExitCode);
   }
 
+#if !defined(PRODUCT)
+  // Constant true in PRODUCT mode.
   if (generate_script_snapshot ||
       generate_full_snapshot_after_run ||
       run_full_snapshot) {
     vm_options.AddArgument("--load_deferred_eagerly");
   }
+#endif
 
 #if defined(DART_PRECOMPILER) && !defined(DART_NO_SNAPSHOT)
   // Always set --precompilation with dart_noopt.
diff --git a/runtime/bin/secure_socket.cc b/runtime/bin/secure_socket.cc
index f63d9d0..7d79dc6 100644
--- a/runtime/bin/secure_socket.cc
+++ b/runtime/bin/secure_socket.cc
@@ -29,6 +29,15 @@
 
 #include "include/dart_api.h"
 
+// Return the error from the containing function if handle is an error handle.
+#define RETURN_IF_ERROR(handle)                                                \
+  {                                                                            \
+    Dart_Handle __handle = handle;                                             \
+    if (Dart_IsError((__handle))) {                                            \
+      return __handle;                                                         \
+    }                                                                          \
+  }
+
 namespace dart {
 namespace bin {
 
@@ -103,13 +112,30 @@
 }
 
 
-static void SetFilter(Dart_NativeArguments args, SSLFilter* filter) {
-  Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
+static void DeleteFilter(
+    void* isolate_data,
+    Dart_WeakPersistentHandle handle,
+    void* context_pointer) {
+  SSLFilter* filter = reinterpret_cast<SSLFilter*>(context_pointer);
+  delete filter;
+}
+
+
+static Dart_Handle SetFilter(Dart_NativeArguments args, SSLFilter* filter) {
+  ASSERT(filter != NULL);
+  Dart_Handle dart_this = Dart_GetNativeArgument(args, 0);
+  RETURN_IF_ERROR(dart_this);
   ASSERT(Dart_IsInstance(dart_this));
-  ThrowIfError(Dart_SetNativeInstanceField(
+  Dart_Handle err = Dart_SetNativeInstanceField(
       dart_this,
       kSSLFilterNativeFieldIndex,
-      reinterpret_cast<intptr_t>(filter)));
+      reinterpret_cast<intptr_t>(filter));
+  RETURN_IF_ERROR(err);
+  Dart_NewWeakPersistentHandle(dart_this,
+                               reinterpret_cast<void*>(filter),
+                               sizeof(*filter),
+                               DeleteFilter);
+  return Dart_Null();
 }
 
 
@@ -134,19 +160,22 @@
 }
 
 
-static void SetSecurityContext(Dart_NativeArguments args,
-                               SSL_CTX* context) {
+static Dart_Handle SetSecurityContext(Dart_NativeArguments args,
+                                      SSL_CTX* context) {
   const int approximate_size_of_context = 1500;
-  Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
+  Dart_Handle dart_this = Dart_GetNativeArgument(args, 0);
+  RETURN_IF_ERROR(dart_this);
   ASSERT(Dart_IsInstance(dart_this));
-  ThrowIfError(Dart_SetNativeInstanceField(
+  Dart_Handle err = Dart_SetNativeInstanceField(
       dart_this,
       kSecurityContextNativeFieldIndex,
-      reinterpret_cast<intptr_t>(context)));
+      reinterpret_cast<intptr_t>(context));
+  RETURN_IF_ERROR(err);
   Dart_NewWeakPersistentHandle(dart_this,
                                context,
                                approximate_size_of_context,
                                FreeSecurityContext);
+  return Dart_Null();
 }
 
 
@@ -171,9 +200,19 @@
 
 void FUNCTION_NAME(SecureSocket_Init)(Dart_NativeArguments args) {
   Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
-  SSLFilter* filter = new SSLFilter;
-  SetFilter(args, filter);
-  filter->Init(dart_this);
+  SSLFilter* filter = new SSLFilter();
+  Dart_Handle err = SetFilter(args, filter);
+  if (Dart_IsError(err)) {
+    delete filter;
+    Dart_PropagateError(err);
+  }
+  err = filter->Init(dart_this);
+  if (Dart_IsError(err)) {
+    // The finalizer was set up by SetFilter. It will delete `filter` if there
+    // is an error.
+    filter->Destroy();
+    Dart_PropagateError(err);
+  }
 }
 
 
@@ -215,9 +254,13 @@
 
 void FUNCTION_NAME(SecureSocket_Destroy)(Dart_NativeArguments args) {
   SSLFilter* filter = GetFilter(args);
-  SetFilter(args, NULL);
+  // The SSLFilter is deleted in the finalizer for the Dart object created by
+  // SetFilter. There is no need to NULL-out the native field for the SSLFilter
+  // here because the SSLFilter won't be deleted until the finalizer for the
+  // Dart object runs while the Dart object is being GCd. This approach avoids a
+  // leak if Destroy isn't called, and avoids a NULL-dereference if Destroy is
+  // called more than once.
   filter->Destroy();
-  delete filter;
 }
 
 
@@ -271,7 +314,8 @@
 
 void FUNCTION_NAME(SecureSocket_PeerCertificate)
     (Dart_NativeArguments args) {
-  Dart_SetReturnValue(args, GetFilter(args)->PeerCertificate());
+  Dart_Handle cert = ThrowIfError(GetFilter(args)->PeerCertificate());
+  Dart_SetReturnValue(args, cert);
 }
 
 
@@ -281,19 +325,34 @@
 }
 
 
+static void ReleaseCertificate(
+    void* isolate_data,
+    Dart_WeakPersistentHandle handle,
+    void* context_pointer) {
+  X509* cert = reinterpret_cast<X509*>(context_pointer);
+  X509_free(cert);
+}
+
+
+// Returns the handle for a Dart object wrapping the X509 certificate object.
+// The caller should own a reference to the X509 object whose reference count
+// won't drop to zero before the ReleaseCertificate finalizer runs.
 static Dart_Handle WrappedX509Certificate(X509* certificate) {
+  const intptr_t approximate_size_of_certificate = 1500;
   if (certificate == NULL) {
     return Dart_Null();
   }
   Dart_Handle x509_type =
       DartUtils::GetDartType(DartUtils::kIOLibURL, "X509Certificate");
   if (Dart_IsError(x509_type)) {
+    X509_free(certificate);
     return x509_type;
   }
   Dart_Handle arguments[] = { NULL };
   Dart_Handle result =
       Dart_New(x509_type, DartUtils::NewString("_"), 0, arguments);
   if (Dart_IsError(result)) {
+    X509_free(certificate);
     return result;
   }
   ASSERT(Dart_IsInstance(result));
@@ -302,8 +361,13 @@
       kX509NativeFieldIndex,
       reinterpret_cast<intptr_t>(certificate));
   if (Dart_IsError(status)) {
+    X509_free(certificate);
     return status;
   }
+  Dart_NewWeakPersistentHandle(result,
+                               reinterpret_cast<void*>(certificate),
+                               approximate_size_of_certificate,
+                               ReleaseCertificate);
   return result;
 }
 
@@ -326,6 +390,11 @@
   if (Dart_IsNull(callback)) {
     return 0;
   }
+
+  // Upref since the Dart X509 object may outlive the SecurityContext.
+  if (certificate != NULL) {
+    X509_up_ref(certificate);
+  }
   Dart_Handle args[1];
   args[0] = WrappedX509Certificate(certificate);
   if (Dart_IsError(args[0])) {
@@ -354,7 +423,11 @@
   SSL_CTX_set_min_version(context, TLS1_VERSION);
   SSL_CTX_set_cipher_list(context, "HIGH:MEDIUM");
   SSL_CTX_set_cipher_list_tls11(context, "HIGH:MEDIUM");
-  SetSecurityContext(args, context);
+  Dart_Handle err = SetSecurityContext(args, context);
+  if (Dart_IsError(err)) {
+    SSL_CTX_free(context);
+    Dart_PropagateError(err);
+  }
 }
 
 
@@ -1154,7 +1227,7 @@
 }
 
 
-void SSLFilter::Init(Dart_Handle dart_this) {
+Dart_Handle SSLFilter::Init(Dart_Handle dart_this) {
   if (!library_initialized_) {
     InitializeLibrary();
   }
@@ -1168,24 +1241,40 @@
   bad_certificate_callback_ = Dart_NewPersistentHandle(Dart_Null());
   ASSERT(bad_certificate_callback_ != NULL);
 
-  InitializeBuffers(dart_this);
+  // Caller handles cleanup on an error.
+  return InitializeBuffers(dart_this);
 }
 
 
-void SSLFilter::InitializeBuffers(Dart_Handle dart_this) {
+Dart_Handle SSLFilter::InitializeBuffers(Dart_Handle dart_this) {
   // Create SSLFilter buffers as ExternalUint8Array objects.
-  Dart_Handle dart_buffers_object = ThrowIfError(
-      Dart_GetField(dart_this, DartUtils::NewString("buffers")));
-  Dart_Handle secure_filter_impl_type =
-      Dart_InstanceGetType(dart_this);
-  Dart_Handle dart_buffer_size = ThrowIfError(
-      Dart_GetField(secure_filter_impl_type, DartUtils::NewString("SIZE")));
-  int64_t buffer_size = DartUtils::GetIntegerValue(dart_buffer_size);
-  Dart_Handle dart_encrypted_buffer_size = ThrowIfError(
-      Dart_GetField(secure_filter_impl_type,
-                    DartUtils::NewString("ENCRYPTED_SIZE")));
-  int64_t encrypted_buffer_size =
-      DartUtils::GetIntegerValue(dart_encrypted_buffer_size);
+  Dart_Handle buffers_string = DartUtils::NewString("buffers");
+  RETURN_IF_ERROR(buffers_string);
+  Dart_Handle dart_buffers_object = Dart_GetField(dart_this, buffers_string);
+  RETURN_IF_ERROR(dart_buffers_object);
+  Dart_Handle secure_filter_impl_type = Dart_InstanceGetType(dart_this);
+  RETURN_IF_ERROR(secure_filter_impl_type);
+  Dart_Handle size_string = DartUtils::NewString("SIZE");
+  RETURN_IF_ERROR(size_string);
+  Dart_Handle dart_buffer_size = Dart_GetField(
+      secure_filter_impl_type, size_string);
+  RETURN_IF_ERROR(dart_buffer_size);
+
+  int64_t buffer_size = 0;
+  Dart_Handle err = Dart_IntegerToInt64(dart_buffer_size, &buffer_size);
+  RETURN_IF_ERROR(err);
+
+  Dart_Handle encrypted_size_string = DartUtils::NewString("ENCRYPTED_SIZE");
+  RETURN_IF_ERROR(encrypted_size_string);
+
+  Dart_Handle dart_encrypted_buffer_size = Dart_GetField(
+      secure_filter_impl_type, encrypted_size_string);
+  RETURN_IF_ERROR(dart_encrypted_buffer_size);
+
+  int64_t encrypted_buffer_size = 0;
+  err = Dart_IntegerToInt64(dart_encrypted_buffer_size, &encrypted_buffer_size);
+  RETURN_IF_ERROR(err);
+
   if (buffer_size <= 0 || buffer_size > 1 * MB) {
     FATAL("Invalid buffer size in _ExternalBuffer");
   }
@@ -1195,21 +1284,44 @@
   buffer_size_ = static_cast<int>(buffer_size);
   encrypted_buffer_size_ = static_cast<int>(encrypted_buffer_size);
 
-
   Dart_Handle data_identifier = DartUtils::NewString("data");
+  RETURN_IF_ERROR(data_identifier);
+
+  for (int i = 0; i < kNumBuffers; i++) {
+    int size = isBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_;
+    buffers_[i] = new uint8_t[size];
+    ASSERT(buffers_[i] != NULL);
+    dart_buffer_objects_[i] = NULL;
+  }
+
+  Dart_Handle result = Dart_Null();
   for (int i = 0; i < kNumBuffers; ++i) {
     int size = isBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_;
-    dart_buffer_objects_[i] =
-        Dart_NewPersistentHandle(Dart_ListGetAt(dart_buffers_object, i));
+    result = Dart_ListGetAt(dart_buffers_object, i);
+    if (Dart_IsError(result)) {
+      break;
+    }
+
+    dart_buffer_objects_[i] = Dart_NewPersistentHandle(result);
     ASSERT(dart_buffer_objects_[i] != NULL);
-    buffers_[i] = new uint8_t[size];
-    Dart_Handle data = ThrowIfError(
-        Dart_NewExternalTypedData(Dart_TypedData_kUint8, buffers_[i], size));
-    ThrowIfError(
-        Dart_SetField(Dart_HandleFromPersistent(dart_buffer_objects_[i]),
-                      data_identifier,
-                      data));
+    Dart_Handle data =
+        Dart_NewExternalTypedData(Dart_TypedData_kUint8, buffers_[i], size);
+    if (Dart_IsError(data)) {
+      result = data;
+      break;
+    }
+    result = Dart_HandleFromPersistent(dart_buffer_objects_[i]);
+    if (Dart_IsError(result)) {
+      break;
+    }
+    result = Dart_SetField(result, data_identifier, data);
+    if (Dart_IsError(result)) {
+      break;
+    }
   }
+
+  // Caller handles cleanup on an error.
+  return result;
 }
 
 
@@ -1241,12 +1353,10 @@
 
 
 Dart_Handle SSLFilter::PeerCertificate() {
+  // SSL_get_peer_certificate incs the refcount of certificate. X509_free is
+  // called by the finalizer set up by WrappedX509Certificate.
   X509* certificate = SSL_get_peer_certificate(ssl_);
-  Dart_Handle x509_object = WrappedX509Certificate(certificate);
-  if (Dart_IsError(x509_object)) {
-    Dart_PropagateError(x509_object);
-  }
-  return x509_object;
+  return WrappedX509Certificate(certificate);
 }
 
 
@@ -1484,7 +1594,7 @@
 }
 
 
-void SSLFilter::Destroy() {
+SSLFilter::~SSLFilter() {
   if (ssl_ != NULL) {
     SSL_free(ssl_);
     ssl_ = NULL;
@@ -1498,13 +1608,37 @@
     hostname_ = NULL;
   }
   for (int i = 0; i < kNumBuffers; ++i) {
-    Dart_DeletePersistentHandle(dart_buffer_objects_[i]);
-    delete[] buffers_[i];
+    if (buffers_[i] != NULL) {
+      delete[] buffers_[i];
+      buffers_[i] = NULL;
+    }
   }
-  Dart_DeletePersistentHandle(string_start_);
-  Dart_DeletePersistentHandle(string_length_);
-  Dart_DeletePersistentHandle(handshake_complete_);
-  Dart_DeletePersistentHandle(bad_certificate_callback_);
+}
+
+
+void SSLFilter::Destroy() {
+  for (int i = 0; i < kNumBuffers; ++i) {
+    if (dart_buffer_objects_[i] != NULL) {
+      Dart_DeletePersistentHandle(dart_buffer_objects_[i]);
+      dart_buffer_objects_[i] = NULL;
+    }
+  }
+  if (string_start_ != NULL) {
+    Dart_DeletePersistentHandle(string_start_);
+    string_start_ = NULL;
+  }
+  if (string_length_ != NULL) {
+    Dart_DeletePersistentHandle(string_length_);
+    string_length_ = NULL;
+  }
+  if (handshake_complete_ != NULL) {
+    Dart_DeletePersistentHandle(handshake_complete_);
+    handshake_complete_ = NULL;
+  }
+  if (bad_certificate_callback_ != NULL) {
+    Dart_DeletePersistentHandle(bad_certificate_callback_);
+    bad_certificate_callback_ = NULL;
+  }
 }
 
 
diff --git a/runtime/bin/secure_socket.h b/runtime/bin/secure_socket.h
index bd5eda3..754d240 100644
--- a/runtime/bin/secure_socket.h
+++ b/runtime/bin/secure_socket.h
@@ -62,7 +62,9 @@
         in_handshake_(false),
         hostname_(NULL) { }
 
-  void Init(Dart_Handle dart_this);
+  ~SSLFilter();
+
+  Dart_Handle Init(Dart_Handle dart_this);
   void Connect(const char* hostname,
                SSL_CTX* context,
                bool is_server,
@@ -120,7 +122,7 @@
   static bool isBufferEncrypted(int i) {
     return static_cast<BufferIndex>(i) >= kFirstEncrypted;
   }
-  void InitializeBuffers(Dart_Handle dart_this);
+  Dart_Handle InitializeBuffers(Dart_Handle dart_this);
   void InitializePlatformData();
 
   DISALLOW_COPY_AND_ASSIGN(SSLFilter);
diff --git a/runtime/bin/secure_socket_patch.dart b/runtime/bin/secure_socket_patch.dart
index ccfc1c1..455b132 100644
--- a/runtime/bin/secure_socket_patch.dart
+++ b/runtime/bin/secure_socket_patch.dart
@@ -137,49 +137,34 @@
   static final SecurityContext defaultContext =
       new _SecurityContext().._trustBuiltinRoots();
 
-  void usePrivateKey(String keyFile, {String password}) {
-    usePrivateKeySync(keyFile, password: password);
-  }
-  void usePrivateKeySync(String keyFile, {String password}) {
-    List<int> bytes = (new File(keyFile)).readAsBytesSync();
+  void usePrivateKey(String file, {String password}) {
+    List<int> bytes = (new File(file)).readAsBytesSync();
     usePrivateKeyBytes(bytes, password: password);
   }
   void usePrivateKeyBytes(List<int> keyBytes, {String password})
       native "SecurityContext_UsePrivateKeyBytes";
 
   void setTrustedCertificates(String file, {String password}) {
-    setTrustedCertificatesSync(file, password: password);
-  }
-  void setTrustedCertificatesSync(String file, {String password}) {
     List<int> bytes = (new File(file)).readAsBytesSync();
     setTrustedCertificatesBytes(bytes, password: password);
   }
   void setTrustedCertificatesBytes(List<int> certBytes, {String password})
       native "SecurityContext_SetTrustedCertificatesBytes";
 
-  void useCertificateChain({String file, String directory, String password}) {
-    if (directory != null) {
-      throw new UnsupportedError(
-          "The directory argument to useCertificateChain is not supported.");
-    }
-    useCertificateChainSync(file, password: password);
-  }
-  void useCertificateChainSync(String chainFile, {String password}) {
-    List<int> bytes = (new File(chainFile)).readAsBytesSync();
+  void useCertificateChain(String file, {String password}) {
+    List<int> bytes = (new File(file)).readAsBytesSync();
     useCertificateChainBytes(bytes, password: password);
   }
   void useCertificateChainBytes(List<int> chainBytes, {String password})
       native "SecurityContext_UseCertificateChainBytes";
 
   void setClientAuthorities(String file, {String password}) {
-    setClientAuthoritiesSync(file, password: password);
-  }
-  void setClientAuthoritiesSync(String file, {String password}) {
     List<int> bytes = (new File(file)).readAsBytesSync();
     setClientAuthoritiesBytes(bytes, password: password);
   }
   void setClientAuthoritiesBytes(List<int> authCertBytes, {String password})
       native "SecurityContext_SetClientAuthoritiesBytes";
+
   void setAlpnProtocols(List<String> protocols, bool isServer) {
     Uint8List encodedProtocols =
         SecurityContext._protocolsToLengthEncoding(protocols);
diff --git a/runtime/bin/stdio_patch.dart b/runtime/bin/stdio_patch.dart
index fbc3083..7e66009 100644
--- a/runtime/bin/stdio_patch.dart
+++ b/runtime/bin/stdio_patch.dart
@@ -32,7 +32,7 @@
   static int _socketType(nativeSocket) {
     var result = _getSocketType(nativeSocket);
     if (result is OSError) {
-      throw new FileSystemException("Error retreiving socket type", "", result);
+      throw new FileSystemException("Error retrieving socket type", "", result);
     }
     return result;
   }
diff --git a/runtime/lib/bool.cc b/runtime/lib/bool.cc
index b536ccf..dcb1952 100644
--- a/runtime/lib/bool.cc
+++ b/runtime/lib/bool.cc
@@ -21,7 +21,7 @@
   GET_NATIVE_ARGUMENT(Bool, default_value, arguments->NativeArgAt(2));
   // Call the embedder to supply us with the environment.
   const String& env_value =
-      String::Handle(Api::CallEnvironmentCallback(thread, name));
+      String::Handle(Api::GetEnvironmentValue(thread, name));
   if (!env_value.IsNull()) {
     if (Symbols::True().Equals(env_value)) {
       return Bool::True().raw();
diff --git a/runtime/lib/core_patch.dart b/runtime/lib/core_patch.dart
index 11e307a..13f7513 100644
--- a/runtime/lib/core_patch.dart
+++ b/runtime/lib/core_patch.dart
@@ -61,6 +61,7 @@
         yieldEachIterator = null;
       }
       isYieldEach = false;
+      // moveNextFn() will update the values of isYieldEach and _current.
       if (!moveNextFn(this)) {
         moveNextFn = null;
         _current = null;
diff --git a/runtime/lib/integers.cc b/runtime/lib/integers.cc
index 9478fcc..e75ecab 100644
--- a/runtime/lib/integers.cc
+++ b/runtime/lib/integers.cc
@@ -237,7 +237,7 @@
   GET_NATIVE_ARGUMENT(Integer, default_value, arguments->NativeArgAt(2));
   // Call the embedder to supply us with the environment.
   const String& env_value =
-      String::Handle(Api::CallEnvironmentCallback(thread, name));
+      String::Handle(Api::GetEnvironmentValue(thread, name));
   if (!env_value.IsNull()) {
     const Integer& result = Integer::Handle(ParseInteger(env_value));
     if (!result.IsNull()) {
diff --git a/runtime/lib/isolate.cc b/runtime/lib/isolate.cc
index f6d248a..fb51c07 100644
--- a/runtime/lib/isolate.cc
+++ b/runtime/lib/isolate.cc
@@ -151,8 +151,8 @@
       return;
     }
 
-    Dart_IsolateFlags api_flags;
-    state_->isolate_flags()->CopyTo(&api_flags);
+    // Make a copy of the state's isolate flags and hand it to the callback.
+    Dart_IsolateFlags api_flags = *(state_->isolate_flags());
 
     Isolate* isolate = reinterpret_cast<Isolate*>(
         (callback)(state_->script_url(),
@@ -391,7 +391,10 @@
   // If we were passed a value then override the default flags state for
   // checked mode.
   if (!checked.IsNull()) {
-    state->isolate_flags()->set_checked(checked.value());
+    bool val = checked.value();
+    Dart_IsolateFlags* flags = state->isolate_flags();
+    flags->enable_asserts = val;
+    flags->enable_type_checks = val;
   }
 
   ThreadPool::Task* spawn_task = new SpawnIsolateTask(state);
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index 10b39ce..aaa28e1 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -270,7 +270,7 @@
   args.SetAt(0, MirrorReference::Handle(MirrorReference::New(func)));
 
   String& name = String::Handle(func.name());
-  name = String::IdentifierPrettyNameRetainPrivate(name);
+  name = String::ScrubNameRetainPrivate(name);
   args.SetAt(1, name);
   args.SetAt(2, owner_mirror);
   args.SetAt(3, instantiator);
@@ -689,7 +689,7 @@
     }
     // An uninitialized field was found.  Check for a getter in the field's
     // owner classs.
-    const Class& klass = Class::Handle(field.owner());
+    const Class& klass = Class::Handle(field.Owner());
     const String& internal_getter_name =
         String::Handle(Field::GetterName(getter_name));
     getter = klass.LookupStaticFunction(internal_getter_name);
@@ -883,7 +883,7 @@
     klass = Function::Cast(decl).origin();
     library = klass.library();
   } else if (decl.IsField()) {
-    klass = Field::Cast(decl).origin();
+    klass = Field::Cast(decl).Origin();
     library = klass.library();
   } else if (decl.IsLibrary()) {
     library ^= decl.raw();
@@ -1993,7 +1993,7 @@
     token_pos = cls.token_pos();
   } else if (decl.IsField()) {
     const Field& field = Field::Cast(decl);
-    script = field.script();
+    script = field.Script();
     token_pos = field.token_pos();
   } else if (decl.IsTypeParameter()) {
     const TypeParameter& type_var = TypeParameter::Cast(decl);
diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc
index c34552d..09e4808 100644
--- a/runtime/lib/object.cc
+++ b/runtime/lib/object.cc
@@ -280,7 +280,7 @@
           location, instance_type_name, type_name,
           dst_name, Object::null_string());
     } else {
-      ASSERT(isolate->flags().type_checks());
+      ASSERT(isolate->type_checks());
       bound_error_message = String::New(bound_error.ToErrorCString());
       Exceptions::CreateAndThrowTypeError(
           location, instance_type_name, Symbols::Empty(),
diff --git a/runtime/lib/regexp.cc b/runtime/lib/regexp.cc
index 14bf14f..47b4245 100644
--- a/runtime/lib/regexp.cc
+++ b/runtime/lib/regexp.cc
@@ -15,7 +15,6 @@
 namespace dart {
 
 DECLARE_FLAG(bool, trace_irregexp);
-DECLARE_FLAG(bool, interpret_irregexp);
 
 
 DEFINE_NATIVE_ENTRY(JSSyntaxRegExp_factory, 4) {
diff --git a/runtime/lib/string.cc b/runtime/lib/string.cc
index 62e5aac..2821146 100644
--- a/runtime/lib/string.cc
+++ b/runtime/lib/string.cc
@@ -20,7 +20,7 @@
   GET_NATIVE_ARGUMENT(String, default_value, arguments->NativeArgAt(2));
   // Call the embedder to supply us with the environment.
   const String& env_value =
-      String::Handle(Api::CallEnvironmentCallback(thread, name));
+      String::Handle(Api::GetEnvironmentValue(thread, name));
   if (!env_value.IsNull()) {
     return Symbols::New(env_value);
   }
diff --git a/runtime/observatory/lib/elements.dart b/runtime/observatory/lib/elements.dart
index e485407..4863c2c 100644
--- a/runtime/observatory/lib/elements.dart
+++ b/runtime/observatory/lib/elements.dart
@@ -45,6 +45,7 @@
 export 'package:observatory/src/elements/objectpool_view.dart';
 export 'package:observatory/src/elements/observatory_application.dart';
 export 'package:observatory/src/elements/observatory_element.dart';
+export 'package:observatory/src/elements/persistent_handles.dart';
 export 'package:observatory/src/elements/ports.dart';
 export 'package:observatory/src/elements/script_inset.dart';
 export 'package:observatory/src/elements/script_ref.dart';
diff --git a/runtime/observatory/lib/elements.html b/runtime/observatory/lib/elements.html
index 1f89cbd..4e84fec 100644
--- a/runtime/observatory/lib/elements.html
+++ b/runtime/observatory/lib/elements.html
@@ -38,6 +38,7 @@
 <link rel="import" href="src/elements/objectpool_view.html">
 <link rel="import" href="src/elements/observatory_application.html">
 <link rel="import" href="src/elements/observatory_element.html">
+<link rel="import" href="src/elements/persistent_handles.html">
 <link rel="import" href="src/elements/ports.html">
 <link rel="import" href="src/elements/script_inset.html">
 <link rel="import" href="src/elements/script_ref.html">
diff --git a/runtime/observatory/lib/src/app/application.dart b/runtime/observatory/lib/src/app/application.dart
index bda98c0..644b659 100644
--- a/runtime/observatory/lib/src/app/application.dart
+++ b/runtime/observatory/lib/src/app/application.dart
@@ -139,6 +139,7 @@
     _pageRegistry.add(new IsolateReconnectPage(this));
     _pageRegistry.add(new ErrorViewPage(this));
     _pageRegistry.add(new MetricsPage(this));
+    _pageRegistry.add(new PersistentHandlesPage(this));
     _pageRegistry.add(new PortsPage(this));
     _pageRegistry.add(new LoggingPage(this));
     _pageRegistry.add(new TimelinePage(this));
diff --git a/runtime/observatory/lib/src/app/page.dart b/runtime/observatory/lib/src/app/page.dart
index 6be5e88..b2216e4 100644
--- a/runtime/observatory/lib/src/app/page.dart
+++ b/runtime/observatory/lib/src/app/page.dart
@@ -266,6 +266,21 @@
   }
 }
 
+class PersistentHandlesPage extends SimplePage {
+  PersistentHandlesPage(app)
+      : super('persistent-handles', 'persistent-handles-page', app);
+
+  void _visit(Uri uri) {
+    super._visit(uri);
+    getIsolate(uri).then((isolate) {
+      if (element != null) {
+        PersistentHandlesPageElement page = element;
+        page.isolate = isolate;
+      }
+    });
+  }
+}
+
 class HeapMapPage extends SimplePage {
   HeapMapPage(app) : super('heap-map', 'heap-map', app);
 
diff --git a/runtime/observatory/lib/src/elements/debugger.dart b/runtime/observatory/lib/src/elements/debugger.dart
index 3bf25b5..6595447 100644
--- a/runtime/observatory/lib/src/elements/debugger.dart
+++ b/runtime/observatory/lib/src/elements/debugger.dart
@@ -1492,7 +1492,7 @@
     warnOutOfDate();
   }
 
-  void _reportIsolateError(Isolate isolate) {
+  void _reportIsolateError(Isolate isolate, String eventKind) {
     if (isolate == null) {
       return;
     }
@@ -1501,14 +1501,26 @@
       return;
     }
     console.newline();
-    console.printBold('Isolate exited due to an unhandled exception:');
+    if (eventKind == ServiceEvent.kPauseException) {
+      console.printBold('Isolate will exit due to an unhandled exception:');
+    } else {
+      console.printBold('Isolate has exited due to an unhandled exception:');
+    }
     console.print(error.message);
     console.newline();
-    console.printBold("Type 'set break-on-exception Unhandled' to pause the"
-                      " isolate when an unhandled exception occurs.");
-    console.newline();
-    console.printBold("You can make this the default by running with "
-                      "--pause-isolates-on-unhandled-exceptions");
+    if (eventKind == ServiceEvent.kPauseException &&
+        (error.exception.isStackOverflowError ||
+         error.exception.isOutOfMemoryError)) {
+      console.printBold(
+          'When an unhandled stack overflow or OOM exception occurs, the VM '
+          'has run out of memory and cannot keep the stack alive while '
+          'paused.');
+    } else {
+      console.printBold("Type 'set break-on-exception Unhandled' to pause the"
+                        " isolate when an unhandled exception occurs.");
+      console.printBold("You can make this the default by running with "
+                        "--pause-isolates-on-unhandled-exceptions");
+    }
   }
 
   void _reportPause(ServiceEvent event) {
@@ -1520,7 +1532,12 @@
       console.print(
           "Paused at isolate exit "
           "(type 'continue' or [F7] to exit the isolate')");
-      _reportIsolateError(isolate);
+      _reportIsolateError(isolate, event.kind);
+    } else if (event.kind == ServiceEvent.kPauseException) {
+      console.print(
+          "Paused at an unhandled exception "
+          "(type 'continue' or [F7] to exit the isolate')");
+      _reportIsolateError(isolate, event.kind);
     } else if (stack['frames'].length > 0) {
       Frame frame = stack['frames'][0];
       var script = frame.location.script;
diff --git a/runtime/observatory/lib/src/elements/isolate_summary.html b/runtime/observatory/lib/src/elements/isolate_summary.html
index c146bfa..64361ed 100644
--- a/runtime/observatory/lib/src/elements/isolate_summary.html
+++ b/runtime/observatory/lib/src/elements/isolate_summary.html
@@ -64,11 +64,13 @@
         <template if="{{ isolate.pauseEvent.kind == 'PauseException' }}">
           by exception
         </template>
-        at
-        <function-ref ref="{{ isolate.topFrame.function }}">
-        </function-ref>
-        (<source-link location="{{ isolate.topFrame.location }}">
-        </source-link>)
+        <template if="{{ isolate.topFrame != null }}">
+          at
+          <function-ref ref="{{ isolate.topFrame.function }}">
+          </function-ref>
+          (<source-link location="{{ isolate.topFrame.location }}">
+          </source-link>)
+        </template>
       </template>
     </template>
 
@@ -168,6 +170,11 @@
         </div>
         <div class="memberItem">
           <div class="memberValue">
+            See <a on-click="{{ goto }}" _href="{{ gotoLink('/persistent-handles', isolate) }}">persistent handles</a>
+          </div>
+        </div>
+        <div class="memberItem">
+          <div class="memberValue">
             See <a on-click="{{ goto }}" _href="{{ gotoLink('/ports', isolate) }}">ports</a>
           </div>
         </div>
diff --git a/runtime/observatory/lib/src/elements/nav_bar.html b/runtime/observatory/lib/src/elements/nav_bar.html
index c9e6b62..4299d0c 100644
--- a/runtime/observatory/lib/src/elements/nav_bar.html
+++ b/runtime/observatory/lib/src/elements/nav_bar.html
@@ -207,6 +207,8 @@
                      anchor="metrics"></nav-menu-item>
       <nav-menu-item link="{{ makeLink('/heap-snapshot', isolate) }}"
                      anchor="heap snapshot"></nav-menu-item>
+      <nav-menu-item link="{{ makeLink('/persistent-handles', isolate) }}"
+                     anchor="persistent handles"></nav-menu-item>
       <nav-menu-item link="{{ makeLink('/ports', isolate) }}"
                      anchor="ports"></nav-menu-item>
       <nav-menu-item link="{{ makeLink('/logging', isolate) }}"
diff --git a/runtime/observatory/lib/src/elements/persistent_handles.dart b/runtime/observatory/lib/src/elements/persistent_handles.dart
new file mode 100644
index 0000000..f6ccfaf
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/persistent_handles.dart
@@ -0,0 +1,178 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library persitent_handles_page;
+
+import 'dart:async';
+import 'dart:html';
+import 'observatory_element.dart';
+import 'package:observatory/app.dart';
+import 'package:observatory/elements.dart';
+import 'package:observatory/service.dart';
+import 'package:polymer/polymer.dart';
+
+class WeakPersistentHandlesSortedTable extends SortedTable {
+  factory WeakPersistentHandlesSortedTable() {
+    var columns = [
+      new SortedTableColumn.withFormatter('External Size',
+                                          Utils.formatSize),
+      new SortedTableColumn('Peer'),
+      new SortedTableColumn('Finalizer Callback'),
+      new SortedTableColumn(''),  // Spacer column.
+      new SortedTableColumn('Object'),
+    ];
+    WeakPersistentHandlesSortedTable result =
+        new WeakPersistentHandlesSortedTable._(columns);
+    // Sort by external size.
+    result.sortColumnIndex = 0;
+    return result;
+  }
+
+  WeakPersistentHandlesSortedTable._(columns) : super(columns);
+
+  @override
+  dynamic getSortKeyFor(int row, int col) {
+    return super.getSortKeyFor(row, col);
+  }
+
+  void update(List<ServiceMap> handles, HtmlElement tableBody) {
+    clearRows();
+    for (ServiceMap handle in handles) {
+      var row = [int.parse(handle['externalSize'], onError: (_) => 0),
+                 handle['peer'],
+                 handle['callbackSymbolName'] +
+                 '( ${handle['callbackAddress']} )',
+                 '', // Spacer column.
+                 handle['object']];
+      addRow(new SortedTableRow(row));
+      print(row);
+    }
+    sort();
+    _updateTableInDom(tableBody);
+  }
+
+  void sortAndDisplay(HtmlElement tableBody) {
+    sort();
+    _updateTableInDom(tableBody);
+  }
+
+
+  void _updateTableInDom(HtmlElement tableBody) {
+    assert(tableBody != null);
+    // Resize DOM table.
+    if (tableBody.children.length > sortedRows.length) {
+      // Shrink the table.
+      var deadRows =
+          tableBody.children.length - sortedRows.length;
+      for (var i = 0; i < deadRows; i++) {
+        tableBody.children.removeLast();
+      }
+    } else if (tableBody.children.length < sortedRows.length) {
+      // Grow table.
+      var newRows = sortedRows.length - tableBody.children.length;
+      for (var i = 0; i < newRows; i++) {
+        _addDomRow(tableBody);
+      }
+    }
+    assert(tableBody.children.length == sortedRows.length);
+    // Fill table.
+    for (var i = 0; i < sortedRows.length; i++) {
+      var rowIndex = sortedRows[i];
+      var tr = tableBody.children[i];
+      _fillDomRow(tr, rowIndex);
+    }
+  }
+
+  void _addDomRow(HtmlElement tableBody) {
+    // Add empty dom row.
+    var tr = new TableRowElement();
+
+    var cell;
+
+    cell = tr.insertCell(-1);
+    cell = tr.insertCell(-1);
+    cell = tr.insertCell(-1);
+
+    // Add spacer.
+    cell = tr.insertCell(-1);
+    cell.classes.add('left-border-spacer');
+
+    // Add class ref.
+    cell = tr.insertCell(-1);
+    AnyServiceRefElement objectRef = new Element.tag('any-service-ref');
+    cell.children.add(objectRef);
+
+    // Add row to table.
+    tableBody.children.add(tr);
+  }
+
+  void _fillDomRow(TableRowElement tr, int rowIndex) {
+    var row = rows[rowIndex];
+
+    for (var i = 0; i < row.values.length - 2; i++) {
+      var cell = tr.children[i];
+      cell.title = row.values[i].toString();
+      cell.text = getFormattedValue(rowIndex, i);
+      cell.style.paddingLeft = '1em';
+      cell.style.paddingRight = '1em';
+    }
+
+    final int objectIndex = row.values.length - 1;
+    AnyServiceRefElement objectRef = tr.children[objectIndex].children[0];
+    objectRef.ref = row.values[objectIndex];
+  }
+}
+
+
+@CustomTag('persistent-handles-page')
+class PersistentHandlesPageElement extends ObservatoryElement {
+  PersistentHandlesPageElement.created() : super.created();
+
+  @observable Isolate isolate;
+  @observable var /*ObservableList | ServiceObject*/ persistentHandles;
+  @observable var /*ObservableList | ServiceObject*/ weakPersistentHandles;
+  @observable WeakPersistentHandlesSortedTable weakPersistentHandlesTable;
+  var _weakPersistentHandlesTableBody;
+
+  void isolateChanged(oldValue) {
+    if (isolate != null) {
+      refresh();
+    }
+  }
+
+  @override
+  void attached() {
+    super.attached();
+    _weakPersistentHandlesTableBody =
+        shadowRoot.querySelector('#weakPersistentHandlesTableBody');
+    weakPersistentHandlesTable =
+        new WeakPersistentHandlesSortedTable();
+  }
+
+  Future refresh() {
+    return isolate.getPersistentHandles().then(_refreshView);
+  }
+
+  _refreshView(/*ObservableList | ServiceObject*/ object) {
+    persistentHandles = object['persistentHandles'];
+    weakPersistentHandles = object['weakPersistentHandles'];
+    weakPersistentHandlesTable.update(
+        weakPersistentHandles,
+        _weakPersistentHandlesTableBody);
+  }
+
+  @observable void changeSort(Event e, var detail, Element target) {
+    if (target is TableCellElement) {
+      if (weakPersistentHandlesTable.sortColumnIndex != target.cellIndex) {
+        weakPersistentHandlesTable.sortColumnIndex = target.cellIndex;
+        weakPersistentHandlesTable.sortDescending = true;
+      } else {
+        weakPersistentHandlesTable.sortDescending =
+            !weakPersistentHandlesTable.sortDescending;
+      }
+      weakPersistentHandlesTable.sortAndDisplay(
+          _weakPersistentHandlesTableBody);
+    }
+  }
+}
diff --git a/runtime/observatory/lib/src/elements/persistent_handles.html b/runtime/observatory/lib/src/elements/persistent_handles.html
new file mode 100644
index 0000000..9005494
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/persistent_handles.html
@@ -0,0 +1,106 @@
+<link rel="import" href="../../../../packages/polymer/polymer.html">
+<link rel="import" href="nav_bar.html">
+<link rel="import" href="observatory_element.html">
+
+<polymer-element name="persistent-handles-page" extends="observatory-element">
+  <template>
+    <link rel="stylesheet" href="css/shared.css">
+    <style>
+    .table {
+      border-collapse: collapse!important;
+      margin-bottom: 20px
+      table-layout: fixed;
+      width: 100%;
+    }
+    .table td:nth-of-type(1) {
+      width: 30%;
+    }
+    .th, .td {
+      padding: 8px;
+      vertical-align: top;
+    }
+    .table thead > tr > th {
+      vertical-align: bottom;
+      text-align: left;
+      border-bottom:2px solid #ddd;
+    }
+    .spacer {
+      width: 16px;
+    }
+    .left-border-spacer {
+      width: 16px;
+      border-left: 1px solid;
+    }
+    .clickable {
+      color: #0489c3;
+      text-decoration: none;
+      cursor: pointer;
+    }
+    .clickable:hover {
+      text-decoration: underline;
+      cursor: pointer;
+    }
+    #weakPersistentHandlesTable tr:hover > td {
+      background-color: #F4C7C3;
+    }
+    .nav-option {
+      color: white;
+      float: right;
+      margin: 3px;
+      padding: 8px;
+    }
+    </style>
+    <nav-bar>
+      <top-nav-menu></top-nav-menu>
+      <vm-nav-menu vm="{{ isolate.vm }}"></vm-nav-menu>
+      <isolate-nav-menu isolate="{{ isolate }}"></isolate-nav-menu>
+      <nav-menu link="{{ makeLink('/persistent-handles', isolate) }}" anchor="persistent handles" last="{{ true }}"></nav-menu>
+      <nav-refresh callback="{{ refresh }}"></nav-refresh>
+    </nav-bar>
+    <div class="content-centered-big">
+      <template if="{{ persistentHandles.isEmpty }}">
+        <h1>Persistent Handles (0)</h1>
+        <hr>
+      </template>
+      <template if="{{ persistentHandles.isNotEmpty }}">
+        <h1>Persistent Handles ({{ persistentHandles.length }})</h1>
+        <hr>
+        <curly-block expand="{{ persistentHandles.length <= 8 }}">
+          <div class="memberList">
+            <template repeat="{{ persistentHandle in persistentHandles }}">
+              <div class="memberItem">
+                <div class="memberValue">
+                  <any-service-ref ref="{{ persistentHandle['object'] }}">
+                  </any-service-ref>
+                </div>
+              </div>
+            </template>
+          </div>
+        </curly-block><br><br>
+      </template>
+      <br><br>
+      <template if="{{ weakPersistentHandles.isEmpty }}">
+        <h1>Weak Persistent Handles (0)</h1>
+        <hr>
+      </template>
+      <template if="{{ weakPersistentHandles.isNotEmpty }}">
+        <h1>Weak Persistent Handles ({{ weakPersistentHandles.length }})</h1>
+        <hr>
+      </template>
+      <table id="weakPersistentHandlesTable" class="flex-item-100-percent table">
+        <thead id="weakPersistentHandlesTableHead">
+          <tr>
+            <th on-click="{{changeSort}}" class="clickable" title="External Size">{{ weakPersistentHandlesTable.getColumnLabel(0) }}</th>
+            <th on-click="{{changeSort}}" class="clickable" title="Peer">{{ weakPersistentHandlesTable.getColumnLabel(1) }}</th>
+            <th on-click="{{changeSort}}" class="clickable" title="Finalizer Callback">{{ weakPersistentHandlesTable.getColumnLabel(2) }}</th>
+            <th class="spacer"></th>
+            <th on-click="{{changeSort}}" class="clickable" title="Object">{{ weakPersistentHandlesTable.getColumnLabel(4) }}</th>
+          </tr>
+        </thead>
+        <tbody id="weakPersistentHandlesTableBody">
+        </tbody>
+      </table>
+      <view-footer></view-footer>
+    </div>
+  </template>
+</polymer-element>
diff --git a/runtime/observatory/lib/src/elements/timeline_page.dart b/runtime/observatory/lib/src/elements/timeline_page.dart
index fbecb10..7a70c11 100644
--- a/runtime/observatory/lib/src/elements/timeline_page.dart
+++ b/runtime/observatory/lib/src/elements/timeline_page.dart
@@ -67,6 +67,14 @@
     });
   }
 
+  Future saveTimeline() async {
+    return postMessage('save');
+  }
+
+  Future loadTimeline() async {
+    return postMessage('load');
+  }
+
   _updateSize() {
     IFrameElement e = $['root'];
     final totalHeight = window.innerHeight;
diff --git a/runtime/observatory/lib/src/elements/timeline_page.html b/runtime/observatory/lib/src/elements/timeline_page.html
index 50b063d..d0a2bcd 100644
--- a/runtime/observatory/lib/src/elements/timeline_page.html
+++ b/runtime/observatory/lib/src/elements/timeline_page.html
@@ -15,6 +15,8 @@
       <nav-refresh callback="{{ clear }}" label="Clear"></nav-refresh>
       <nav-refresh callback="{{ recordOn }}" label="Start recording"></nav-refresh>
       <nav-refresh callback="{{ recordOff }}" label="Stop recording"></nav-refresh>
+      <nav-refresh callback="{{ saveTimeline }}" label="Save"></nav-refresh>
+      <nav-refresh callback="{{ loadTimeline }}" label="Load"></nav-refresh>
     </nav-bar>
     <iframe id="root" frameborder="0" src="../../../../timeline.html">
     </iframe>
diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
index 78b6765..b3a06b9 100644
--- a/runtime/observatory/lib/src/service/object.dart
+++ b/runtime/observatory/lib/src/service/object.dart
@@ -389,6 +389,13 @@
       clazz = map['class'];
     }
 
+    // Load the full class object if the isolate is runnable.
+    if (clazz != null) {
+      if (clazz.isolate.runnable) {
+        clazz.load();
+      }
+    }
+
     if (mapIsRef) {
       return;
     }
@@ -1137,7 +1144,7 @@
   @observable bool running = false;
   @observable bool idle = false;
   @observable bool loading = true;
-
+  @observable bool runnable = false;
   @observable bool ioEnabled = false;
 
   final List<String> extensionRPCs = new List<String>();
@@ -1193,6 +1200,10 @@
     return invokeRpc('_getPorts', {});
   }
 
+  Future<ServiceObject> getPersistentHandles() {
+    return invokeRpc('_getPersistentHandles', {});
+  }
+
   Future<List<Class>> getClassRefs() async {
     ServiceMap classList = await invokeRpc('getClassList', {});
     assert(classList.type == 'ClassList');
@@ -1375,7 +1386,7 @@
     }
     _loaded = true;
     loading = false;
-
+    runnable = map['runnable'] == true;
     _upgradeCollection(map, isolate);
     originNumber = int.parse(map['_originNumber'], onError:(_) => null);
     rootLibrary = map['rootLib'];
@@ -1858,6 +1869,7 @@
   void _update(ObservableMap map, bool mapIsRef) {
     _loaded = true;
     _upgradeCollection(map, owner);
+
     assert(map['isolate'] == null || owner == map['isolate']);
     timestamp =
         new DateTime.fromMillisecondsSinceEpoch(map['timestamp']);
@@ -2041,6 +2053,10 @@
   bool get canCache => true;
   bool get immutable => false;
 
+  bool isDart(String libraryName) {
+    return uri == 'dart:$libraryName';
+  }
+
   Library._empty(ServiceObjectOwner owner) : super._empty(owner);
 
   void _update(ObservableMap map, bool mapIsRef) {
@@ -2325,6 +2341,25 @@
   bool get isWeakProperty => kind == 'WeakProperty';
   bool get isClosure => kind == 'Closure';
   bool get isStackTrace => kind == 'StackTrace';
+  bool get isStackOverflowError {
+    if (clazz == null) {
+      return false;
+    }
+    if (clazz.library == null) {
+      return false;
+    }
+    return (clazz.name == 'StackOverflowError') && clazz.library.isDart('core');
+  }
+
+  bool get isOutOfMemoryError {
+    if (clazz == null) {
+      return false;
+    }
+    if (clazz.library == null) {
+      return false;
+    }
+    return (clazz.name == 'OutOfMemoryError') && clazz.library.isDart('core');
+  }
 
   // TODO(turnidge): Is this properly backwards compatible when new
   // instance kinds are added?
diff --git a/runtime/observatory/observatory_sources.gypi b/runtime/observatory/observatory_sources.gypi
index 865f140..a3a2510 100644
--- a/runtime/observatory/observatory_sources.gypi
+++ b/runtime/observatory/observatory_sources.gypi
@@ -119,6 +119,8 @@
     'lib/src/elements/observatory_application.html',
     'lib/src/elements/observatory_element.dart',
     'lib/src/elements/observatory_element.html',
+    'lib/src/elements/persistent_handles.dart',
+    'lib/src/elements/persistent_handles.html',
     'lib/src/elements/ports.dart',
     'lib/src/elements/ports.html',
     'lib/src/elements/script_inset.dart',
diff --git a/runtime/observatory/tests/service/developer_extension_test.dart b/runtime/observatory/tests/service/developer_extension_test.dart
index f8cd30f..5c8e5cd 100644
--- a/runtime/observatory/tests/service/developer_extension_test.dart
+++ b/runtime/observatory/tests/service/developer_extension_test.dart
@@ -152,5 +152,4 @@
   },
 ];
 
-main(args) async => runIsolateTests(args, tests, testeeConcurrent:test,
-                                    trace_compiler: true);
+main(args) async => runIsolateTests(args, tests, testeeConcurrent:test);
diff --git a/runtime/observatory/web/timeline.js b/runtime/observatory/web/timeline.js
index 27f572c..9bdf46a 100644
--- a/runtime/observatory/web/timeline.js
+++ b/runtime/observatory/web/timeline.js
@@ -105,6 +105,85 @@
   }
 }
 
+function saveTimeline() {
+  if (pendingRequests > 0) {
+    var overlay = new tr.ui.b.Overlay();
+    overlay.textContent = 'Cannot save timeline while fetching one.';
+    overlay.title = 'Save error';
+    overlay.visible = true;
+    console.log('cannot save timeline while fetching one.');
+    return;
+  }
+  if (!traceObject ||
+      !traceObject.traceEvents ||
+      (traceObject.traceEvents.length == 0)) {
+    var overlay = new tr.ui.b.Overlay();
+    overlay.textContent = 'Cannot save an empty timeline.';
+    overlay.title = 'Save error';
+    overlay.visible = true;
+    console.log('Cannot save an empty timeline.');
+    return;
+  }
+  var blob = new Blob([JSON.stringify(traceObject)],
+                      {type: 'application/json'});
+  var blobUrl = URL.createObjectURL(blob);
+  var link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
+  link.href = blobUrl;
+  var now = new Date();
+  var defaultFilename = "dart-timeline-" +
+                        now.getFullYear() +
+                        "-" +
+                        now.getMonth() +
+                        "-" +
+                        now.getDate() +
+                        ".json";
+  var filename = window.prompt('Save as', defaultFilename);
+  if (filename) {
+    link.download = filename;
+    link.click();
+  }
+}
+
+function loadTimeline() {
+  if (pendingRequests > 0) {
+    var overlay = new tr.ui.b.Overlay();
+    overlay.textContent = 'Cannot load timeline while fetching one.';
+    overlay.title = 'Save error';
+    overlay.visible = true;
+    console.log('Cannot load timeline while fetching one.');
+    return;
+  }
+  var inputElement = document.createElement('input');
+  inputElement.type = 'file';
+  inputElement.multiple = false;
+
+  var changeFired = false;
+  inputElement.addEventListener('change', function(e) {
+    if (changeFired)
+      return;
+    changeFired = true;
+
+    var file = inputElement.files[0];
+    var reader = new FileReader();
+    reader.onload = function(event) {
+      try {
+        traceObject = JSON.parse(event.target.result);
+        updateTimeline(traceObject);
+      } catch (error) {
+        tr.ui.b.Overlay.showError('Error while loading file: ' + error);
+      }
+    };
+    reader.onerror = function(event) {
+      tr.ui.b.Overlay.showError('Error while loading file: ' + event);
+    };
+    reader.onabort = function(event) {
+      tr.ui.b.Overlay.showError('Error while loading file: ' + event);
+    }
+    reader.readAsText(file);
+  });
+  inputElement.click();
+}
+
 function onMessage(event) {
   var request = JSON.parse(event.data);
   var method = request['method'];
@@ -116,6 +195,12 @@
     case 'clear':
       clearTimeline();
     break;
+    case 'save':
+      saveTimeline();
+    break;
+    case 'load':
+      loadTimeline();
+    break;
     default:
       console.log('Unknown method:' + method + '.');
   }
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 3032412..da20917 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -65,7 +65,7 @@
 cc/Int8ListLengthMaxElements: Skip # Issue 23536, uses 1 GB memory.
 
 [ $arch == mips && $mode == debug ]
-cc/FindCodeObject: Skip # Takes more than 8 minutes. Issue 17440
+cc/FindCodeObject: SkipSlow # Takes more than 8 minutes. Issue 17440
 
 [ $compiler == dart2analyzer ]
 dart/optimized_stacktrace_test: StaticWarning
@@ -76,24 +76,24 @@
 dart/spawn_shutdown_test: Skip  # VM Shutdown test
 
 [ ($runtime == vm || $runtime == dart_precompiled) && $mode == debug && $builder_tag == asan ]
-cc/Dart2JSCompileAll: Skip  # Timeout.
+cc/Dart2JSCompileAll: SkipSlow  # Timeout.
+
+[ $builder_tag == asan ]
+cc/CodeImmutability: Fail,OK # Address Sanitizer turns a crash into a failure.
 
 [ $noopt ]
 dart/byte_array_test: Crash # Incompatible flag --disable_alloc_stubs_after_gc
 
-[ $noopt || $compiler == precompiler ]
+[ $noopt || $compiler == precompiler || $compiler == dart2app ]
 dart/redirection_type_shuffling_test: CompileTimeError # Imports dart:mirrors
-dart/optimized_stacktrace_test: RuntimeError # Expects line and column numbers
 
-[ $compiler == dart2app ]
-dart/optimized_stacktrace_test: RuntimeError # Expects line and column numbers
+[ $noopt || $runtime == dart_precompiled ]
+# Stacktraces in precompilation omit inlined frames.
+dart/inline_stack_frame_test: Pass, RuntimeError
+dart/optimized_stacktrace_test: Pass, RuntimeError
 
-[ $runtime == dart_product ]
-dart/data_uri_spawn_test: Skip # Isolate.spawnUri
-
-[ $runtime == dart_precompiled ]
-dart/inline_stack_frame_test: Fail  # Issue 24783 - inlined frames missing
-dart/data_uri_spawn_test: RuntimeError # Isolate.spawnUri
+[ $runtime == dart_product || $runtime == dart_precompiled ]
+dart/data_uri_spawn_test: SkipByDesign # Isolate.spawnUri
 
 [ $runtime == vm && $mode == product ]
 cc/IsolateSetCheckedMode: Fail,OK  # Expects exact type name.
diff --git a/runtime/third_party/binary_size/README.dart b/runtime/third_party/binary_size/README.dart
new file mode 100644
index 0000000..0f2124e
--- /dev/null
+++ b/runtime/third_party/binary_size/README.dart
@@ -0,0 +1 @@
+A local copy of tools/binary_size from Chromium project.
\ No newline at end of file
diff --git a/runtime/third_party/binary_size/src/binary_size_utils.py b/runtime/third_party/binary_size/src/binary_size_utils.py
new file mode 100644
index 0000000..67335c2
--- /dev/null
+++ b/runtime/third_party/binary_size/src/binary_size_utils.py
@@ -0,0 +1,71 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Common utilities for tools that deal with binary size information.
+"""
+
+import logging
+import re
+
+
+def ParseNm(nm_lines):
+  """Parse nm output, returning data for all relevant (to binary size)
+  symbols and ignoring the rest.
+
+  Args:
+      nm_lines: an iterable over lines of nm output.
+
+  Yields:
+      (symbol name, symbol type, symbol size, source file path).
+
+      Path may be None if nm couldn't figure out the source file.
+  """
+
+  # Match lines with size, symbol, optional location, optional discriminator
+  sym_re = re.compile(r'^([0-9a-f]{8,}) ' # address (8+ hex digits)
+                      '([0-9a-f]{8,}) ' # size (8+ hex digits)
+                      '(.) ' # symbol type, one character
+                      '([^\t]+)' # symbol name, separated from next by tab
+                      '(?:\t(.*):[\d\?]+)?.*$') # location
+  # Match lines with addr but no size.
+  addr_re = re.compile(r'^[0-9a-f]{8,} (.) ([^\t]+)(?:\t.*)?$')
+  # Match lines that don't have an address at all -- typically external symbols.
+  noaddr_re = re.compile(r'^ {8,} (.) (.*)$')
+  # Match lines with no symbol name, only addr and type
+  addr_only_re = re.compile(r'^[0-9a-f]{8,} (.)$')
+
+  seen_lines = set()
+  for line in nm_lines:
+    line = line.rstrip()
+    if line in seen_lines:
+      # nm outputs identical lines at times. We don't want to treat
+      # those as distinct symbols because that would make no sense.
+      continue
+    seen_lines.add(line)
+    match = sym_re.match(line)
+    if match:
+      address, size, sym_type, sym = match.groups()[0:4]
+      size = int(size, 16)
+      if sym_type in ('B', 'b'):
+        continue  # skip all BSS for now.
+      path = match.group(5)
+      yield sym, sym_type, size, path, address
+      continue
+    match = addr_re.match(line)
+    if match:
+      # sym_type, sym = match.groups()[0:2]
+      continue  # No size == we don't care.
+    match = noaddr_re.match(line)
+    if match:
+      sym_type, sym = match.groups()
+      if sym_type in ('U', 'w'):
+        continue  # external or weak symbol
+    match = addr_only_re.match(line)
+    if match:
+      continue  # Nothing to do.
+
+
+    # If we reach this part of the loop, there was something in the
+    # line that we didn't expect or recognize.
+    logging.warning('nm output parser failed to parse: %s', repr(line))
diff --git a/runtime/third_party/binary_size/src/elf_symbolizer.py b/runtime/third_party/binary_size/src/elf_symbolizer.py
new file mode 100644
index 0000000..374063a
--- /dev/null
+++ b/runtime/third_party/binary_size/src/elf_symbolizer.py
@@ -0,0 +1,467 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import collections
+import datetime
+import logging
+import multiprocessing
+import os
+import posixpath
+import Queue
+import re
+import subprocess
+import sys
+import threading
+import time
+
+
+# addr2line builds a possibly infinite memory cache that can exhaust
+# the computer's memory if allowed to grow for too long. This constant
+# controls how many lookups we do before restarting the process. 4000
+# gives near peak performance without extreme memory usage.
+ADDR2LINE_RECYCLE_LIMIT = 4000
+
+
+class ELFSymbolizer(object):
+  """An uber-fast (multiprocessing, pipelined and asynchronous) ELF symbolizer.
+
+  This class is a frontend for addr2line (part of GNU binutils), designed to
+  symbolize batches of large numbers of symbols for a given ELF file. It
+  supports sharding symbolization against many addr2line instances and
+  pipelining of multiple requests per each instance (in order to hide addr2line
+  internals and OS pipe latencies).
+
+  The interface exhibited by this class is a very simple asynchronous interface,
+  which is based on the following three methods:
+  - SymbolizeAsync(): used to request (enqueue) resolution of a given address.
+  - The |callback| method: used to communicated back the symbol information.
+  - Join(): called to conclude the batch to gather the last outstanding results.
+  In essence, before the Join method returns, this class will have issued as
+  many callbacks as the number of SymbolizeAsync() calls. In this regard, note
+  that due to multiprocess sharding, callbacks can be delivered out of order.
+
+  Some background about addr2line:
+  - it is invoked passing the elf path in the cmdline, piping the addresses in
+    its stdin and getting results on its stdout.
+  - it has pretty large response times for the first requests, but it
+    works very well in streaming mode once it has been warmed up.
+  - it doesn't scale by itself (on more cores). However, spawning multiple
+    instances at the same time on the same file is pretty efficient as they
+    keep hitting the pagecache and become mostly CPU bound.
+  - it might hang or crash, mostly for OOM. This class deals with both of these
+    problems.
+
+  Despite the "scary" imports and the multi* words above, (almost) no multi-
+  threading/processing is involved from the python viewpoint. Concurrency
+  here is achieved by spawning several addr2line subprocesses and handling their
+  output pipes asynchronously. Therefore, all the code here (with the exception
+  of the Queue instance in Addr2Line) should be free from mind-blowing
+  thread-safety concerns.
+
+  The multiprocess sharding works as follows:
+  The symbolizer tries to use the lowest number of addr2line instances as
+  possible (with respect of |max_concurrent_jobs|) and enqueue all the requests
+  in a single addr2line instance. For few symbols (i.e. dozens) sharding isn't
+  worth the startup cost.
+  The multiprocess logic kicks in as soon as the queues for the existing
+  instances grow. Specifically, once all the existing instances reach the
+  |max_queue_size| bound, a new addr2line instance is kicked in.
+  In the case of a very eager producer (i.e. all |max_concurrent_jobs| instances
+  have a backlog of |max_queue_size|), back-pressure is applied on the caller by
+  blocking the SymbolizeAsync method.
+
+  This module has been deliberately designed to be dependency free (w.r.t. of
+  other modules in this project), to allow easy reuse in external projects.
+  """
+
+  def __init__(self, elf_file_path, addr2line_path, callback, inlines=False,
+      max_concurrent_jobs=None, addr2line_timeout=30, max_queue_size=50,
+      source_root_path=None, strip_base_path=None):
+    """Args:
+      elf_file_path: path of the elf file to be symbolized.
+      addr2line_path: path of the toolchain's addr2line binary.
+      callback: a callback which will be invoked for each resolved symbol with
+          the two args (sym_info, callback_arg). The former is an instance of
+          |ELFSymbolInfo| and contains the symbol information. The latter is an
+          embedder-provided argument which is passed to SymbolizeAsync().
+      inlines: when True, the ELFSymbolInfo will contain also the details about
+          the outer inlining functions. When False, only the innermost function
+          will be provided.
+      max_concurrent_jobs: Max number of addr2line instances spawned.
+          Parallelize responsibly, addr2line is a memory and I/O monster.
+      max_queue_size: Max number of outstanding requests per addr2line instance.
+      addr2line_timeout: Max time (in seconds) to wait for a addr2line response.
+          After the timeout, the instance will be considered hung and respawned.
+      source_root_path: In some toolchains only the name of the source file is
+          is output, without any path information; disambiguation searches
+          through the source directory specified by |source_root_path| argument
+          for files whose name matches, adding the full path information to the
+          output. For example, if the toolchain outputs "unicode.cc" and there
+          is a file called "unicode.cc" located under |source_root_path|/foo,
+          the tool will replace "unicode.cc" with
+          "|source_root_path|/foo/unicode.cc". If there are multiple files with
+          the same name, disambiguation will fail because the tool cannot
+          determine which of the files was the source of the symbol.
+      strip_base_path: Rebases the symbols source paths onto |source_root_path|
+          (i.e replace |strip_base_path| with |source_root_path).
+    """
+    assert(os.path.isfile(addr2line_path)), 'Cannot find ' + addr2line_path
+    self.elf_file_path = elf_file_path
+    self.addr2line_path = addr2line_path
+    self.callback = callback
+    self.inlines = inlines
+    self.max_concurrent_jobs = (max_concurrent_jobs or
+                                min(multiprocessing.cpu_count(), 4))
+    self.max_queue_size = max_queue_size
+    self.addr2line_timeout = addr2line_timeout
+    self.requests_counter = 0  # For generating monotonic request IDs.
+    self._a2l_instances = []  # Up to |max_concurrent_jobs| _Addr2Line inst.
+
+    # If necessary, create disambiguation lookup table
+    self.disambiguate = source_root_path is not None
+    self.disambiguation_table = {}
+    self.strip_base_path = strip_base_path
+    if(self.disambiguate):
+      self.source_root_path = os.path.abspath(source_root_path)
+      self._CreateDisambiguationTable()
+
+    # Create one addr2line instance. More instances will be created on demand
+    # (up to |max_concurrent_jobs|) depending on the rate of the requests.
+    self._CreateNewA2LInstance()
+
+  def SymbolizeAsync(self, addr, callback_arg=None):
+    """Requests symbolization of a given address.
+
+    This method is not guaranteed to return immediately. It generally does, but
+    in some scenarios (e.g. all addr2line instances have full queues) it can
+    block to create back-pressure.
+
+    Args:
+      addr: address to symbolize.
+      callback_arg: optional argument which will be passed to the |callback|."""
+    assert(isinstance(addr, int))
+
+    # Process all the symbols that have been resolved in the meanwhile.
+    # Essentially, this drains all the addr2line(s) out queues.
+    for a2l_to_purge in self._a2l_instances:
+      a2l_to_purge.ProcessAllResolvedSymbolsInQueue()
+      a2l_to_purge.RecycleIfNecessary()
+
+    # Find the best instance according to this logic:
+    # 1. Find an existing instance with the shortest queue.
+    # 2. If all of instances' queues are full, but there is room in the pool,
+    #    (i.e. < |max_concurrent_jobs|) create a new instance.
+    # 3. If there were already |max_concurrent_jobs| instances and all of them
+    #    had full queues, make back-pressure.
+
+    # 1.
+    def _SortByQueueSizeAndReqID(a2l):
+      return (a2l.queue_size, a2l.first_request_id)
+    a2l = min(self._a2l_instances, key=_SortByQueueSizeAndReqID)
+
+    # 2.
+    if (a2l.queue_size >= self.max_queue_size and
+        len(self._a2l_instances) < self.max_concurrent_jobs):
+      a2l = self._CreateNewA2LInstance()
+
+    # 3.
+    if a2l.queue_size >= self.max_queue_size:
+      a2l.WaitForNextSymbolInQueue()
+
+    a2l.EnqueueRequest(addr, callback_arg)
+
+  def Join(self):
+    """Waits for all the outstanding requests to complete and terminates."""
+    for a2l in self._a2l_instances:
+      a2l.WaitForIdle()
+      a2l.Terminate()
+
+  def _CreateNewA2LInstance(self):
+    assert(len(self._a2l_instances) < self.max_concurrent_jobs)
+    a2l = ELFSymbolizer.Addr2Line(self)
+    self._a2l_instances.append(a2l)
+    return a2l
+
+  def _CreateDisambiguationTable(self):
+    """ Non-unique file names will result in None entries"""
+    start_time = time.time()
+    logging.info('Collecting information about available source files...')
+    self.disambiguation_table = {}
+
+    for root, _, filenames in os.walk(self.source_root_path):
+      for f in filenames:
+        self.disambiguation_table[f] = os.path.join(root, f) if (f not in
+                                       self.disambiguation_table) else None
+    logging.info('Finished collecting information about '
+                 'possible files (took %.1f s).',
+                 (time.time() - start_time))
+
+
+  class Addr2Line(object):
+    """A python wrapper around an addr2line instance.
+
+    The communication with the addr2line process looks as follows:
+      [STDIN]         [STDOUT]  (from addr2line's viewpoint)
+    > f001111
+    > f002222
+                    < Symbol::Name(foo, bar) for f001111
+                    < /path/to/source/file.c:line_number
+    > f003333
+                    < Symbol::Name2() for f002222
+                    < /path/to/source/file.c:line_number
+                    < Symbol::Name3() for f003333
+                    < /path/to/source/file.c:line_number
+    """
+
+    SYM_ADDR_RE = re.compile(r'([^:]+):(\?|\d+).*')
+
+    def __init__(self, symbolizer):
+      self._symbolizer = symbolizer
+      self._lib_file_name = posixpath.basename(symbolizer.elf_file_path)
+
+      # The request queue (i.e. addresses pushed to addr2line's stdin and not
+      # yet retrieved on stdout)
+      self._request_queue = collections.deque()
+
+      # This is essentially len(self._request_queue). It has been optimized to a
+      # separate field because turned out to be a perf hot-spot.
+      self.queue_size = 0
+
+      # Keep track of the number of symbols a process has processed to
+      # avoid a single process growing too big and using all the memory.
+      self._processed_symbols_count = 0
+
+      # Objects required to handle the addr2line subprocess.
+      self._proc = None  # Subprocess.Popen(...) instance.
+      self._thread = None  # Threading.thread instance.
+      self._out_queue = None  # Queue.Queue instance (for buffering a2l stdout).
+      self._RestartAddr2LineProcess()
+
+    def EnqueueRequest(self, addr, callback_arg):
+      """Pushes an address to addr2line's stdin (and keeps track of it)."""
+      self._symbolizer.requests_counter += 1  # For global "age" of requests.
+      req_idx = self._symbolizer.requests_counter
+      self._request_queue.append((addr, callback_arg, req_idx))
+      self.queue_size += 1
+      self._WriteToA2lStdin(addr)
+
+    def WaitForIdle(self):
+      """Waits until all the pending requests have been symbolized."""
+      while self.queue_size > 0:
+        self.WaitForNextSymbolInQueue()
+
+    def WaitForNextSymbolInQueue(self):
+      """Waits for the next pending request to be symbolized."""
+      if not self.queue_size:
+        return
+
+      # This outer loop guards against a2l hanging (detecting stdout timeout).
+      while True:
+        start_time = datetime.datetime.now()
+        timeout = datetime.timedelta(seconds=self._symbolizer.addr2line_timeout)
+
+        # The inner loop guards against a2l crashing (checking if it exited).
+        while (datetime.datetime.now() - start_time < timeout):
+          # poll() returns !None if the process exited. a2l should never exit.
+          if self._proc.poll():
+            logging.warning('addr2line crashed, respawning (lib: %s).' %
+                            self._lib_file_name)
+            self._RestartAddr2LineProcess()
+            # TODO(primiano): the best thing to do in this case would be
+            # shrinking the pool size as, very likely, addr2line is crashed
+            # due to low memory (and the respawned one will die again soon).
+
+          try:
+            lines = self._out_queue.get(block=True, timeout=0.25)
+          except Queue.Empty:
+            # On timeout (1/4 s.) repeat the inner loop and check if either the
+            # addr2line process did crash or we waited its output for too long.
+            continue
+
+          # In nominal conditions, we get straight to this point.
+          self._ProcessSymbolOutput(lines)
+          return
+
+        # If this point is reached, we waited more than |addr2line_timeout|.
+        logging.warning('Hung addr2line process, respawning (lib: %s).' %
+                        self._lib_file_name)
+        self._RestartAddr2LineProcess()
+
+    def ProcessAllResolvedSymbolsInQueue(self):
+      """Consumes all the addr2line output lines produced (without blocking)."""
+      if not self.queue_size:
+        return
+      while True:
+        try:
+          lines = self._out_queue.get_nowait()
+        except Queue.Empty:
+          break
+        self._ProcessSymbolOutput(lines)
+
+    def RecycleIfNecessary(self):
+      """Restarts the process if it has been used for too long.
+
+      A long running addr2line process will consume excessive amounts
+      of memory without any gain in performance."""
+      if self._processed_symbols_count >= ADDR2LINE_RECYCLE_LIMIT:
+        self._RestartAddr2LineProcess()
+
+
+    def Terminate(self):
+      """Kills the underlying addr2line process.
+
+      The poller |_thread| will terminate as well due to the broken pipe."""
+      try:
+        self._proc.kill()
+        self._proc.communicate()  # Essentially wait() without risking deadlock.
+      except Exception:  # An exception while terminating? How interesting.
+        pass
+      self._proc = None
+
+    def _WriteToA2lStdin(self, addr):
+      self._proc.stdin.write('%s\n' % hex(addr))
+      if self._symbolizer.inlines:
+        # In the case of inlines we output an extra blank line, which causes
+        # addr2line to emit a (??,??:0) tuple that we use as a boundary marker.
+        self._proc.stdin.write('\n')
+      self._proc.stdin.flush()
+
+    def _ProcessSymbolOutput(self, lines):
+      """Parses an addr2line symbol output and triggers the client callback."""
+      (_, callback_arg, _) = self._request_queue.popleft()
+      self.queue_size -= 1
+
+      innermost_sym_info = None
+      sym_info = None
+      for (line1, line2) in lines:
+        prev_sym_info = sym_info
+        name = line1 if not line1.startswith('?') else None
+        source_path = None
+        source_line = None
+        m = ELFSymbolizer.Addr2Line.SYM_ADDR_RE.match(line2)
+        if m:
+          if not m.group(1).startswith('?'):
+            source_path = m.group(1)
+            if not m.group(2).startswith('?'):
+              source_line = int(m.group(2))
+        else:
+          logging.warning('Got invalid symbol path from addr2line: %s' % line2)
+
+        # In case disambiguation is on, and needed
+        was_ambiguous = False
+        disambiguated = False
+        if self._symbolizer.disambiguate:
+          if source_path and not posixpath.isabs(source_path):
+            path = self._symbolizer.disambiguation_table.get(source_path)
+            was_ambiguous = True
+            disambiguated = path is not None
+            source_path = path if disambiguated else source_path
+
+          # Use absolute paths (so that paths are consistent, as disambiguation
+          # uses absolute paths)
+          if source_path and not was_ambiguous:
+            source_path = os.path.abspath(source_path)
+
+        if source_path and self._symbolizer.strip_base_path:
+          # Strip the base path
+          source_path = re.sub('^' + self._symbolizer.strip_base_path,
+              self._symbolizer.source_root_path or '', source_path)
+
+        sym_info = ELFSymbolInfo(name, source_path, source_line, was_ambiguous,
+                                 disambiguated)
+        if prev_sym_info:
+          prev_sym_info.inlined_by = sym_info
+        if not innermost_sym_info:
+          innermost_sym_info = sym_info
+
+      self._processed_symbols_count += 1
+      self._symbolizer.callback(innermost_sym_info, callback_arg)
+
+    def _RestartAddr2LineProcess(self):
+      if self._proc:
+        self.Terminate()
+
+      # The only reason of existence of this Queue (and the corresponding
+      # Thread below) is the lack of a subprocess.stdout.poll_avail_lines().
+      # Essentially this is a pipe able to extract a couple of lines atomically.
+      self._out_queue = Queue.Queue()
+
+      # Start the underlying addr2line process in line buffered mode.
+
+      cmd = [self._symbolizer.addr2line_path, '--functions', '--demangle',
+          '--exe=' + self._symbolizer.elf_file_path]
+      if self._symbolizer.inlines:
+        cmd += ['--inlines']
+      self._proc = subprocess.Popen(cmd, bufsize=1, stdout=subprocess.PIPE,
+          stdin=subprocess.PIPE, stderr=sys.stderr, close_fds=True)
+
+      # Start the poller thread, which simply moves atomically the lines read
+      # from the addr2line's stdout to the |_out_queue|.
+      self._thread = threading.Thread(
+          target=ELFSymbolizer.Addr2Line.StdoutReaderThread,
+          args=(self._proc.stdout, self._out_queue, self._symbolizer.inlines))
+      self._thread.daemon = True  # Don't prevent early process exit.
+      self._thread.start()
+
+      self._processed_symbols_count = 0
+
+      # Replay the pending requests on the new process (only for the case
+      # of a hung addr2line timing out during the game).
+      for (addr, _, _) in self._request_queue:
+        self._WriteToA2lStdin(addr)
+
+    @staticmethod
+    def StdoutReaderThread(process_pipe, queue, inlines):
+      """The poller thread fn, which moves the addr2line stdout to the |queue|.
+
+      This is the only piece of code not running on the main thread. It merely
+      writes to a Queue, which is thread-safe. In the case of inlines, it
+      detects the ??,??:0 marker and sends the lines atomically, such that the
+      main thread always receives all the lines corresponding to one symbol in
+      one shot."""
+      try:
+        lines_for_one_symbol = []
+        while True:
+          line1 = process_pipe.readline().rstrip('\r\n')
+          line2 = process_pipe.readline().rstrip('\r\n')
+          if not line1 or not line2:
+            break
+          inline_has_more_lines = inlines and (len(lines_for_one_symbol) == 0 or
+                                  (line1 != '??' and line2 != '??:0'))
+          if not inlines or inline_has_more_lines:
+            lines_for_one_symbol += [(line1, line2)]
+          if inline_has_more_lines:
+            continue
+          queue.put(lines_for_one_symbol)
+          lines_for_one_symbol = []
+        process_pipe.close()
+
+      # Every addr2line processes will die at some point, please die silently.
+      except (IOError, OSError):
+        pass
+
+    @property
+    def first_request_id(self):
+      """Returns the request_id of the oldest pending request in the queue."""
+      return self._request_queue[0][2] if self._request_queue else 0
+
+
+class ELFSymbolInfo(object):
+  """The result of the symbolization passed as first arg. of each callback."""
+
+  def __init__(self, name, source_path, source_line, was_ambiguous=False,
+               disambiguated=False):
+    """All the fields here can be None (if addr2line replies with '??')."""
+    self.name = name
+    self.source_path = source_path
+    self.source_line = source_line
+    # In the case of |inlines|=True, the |inlined_by| points to the outer
+    # function inlining the current one (and so on, to form a chain).
+    self.inlined_by = None
+    self.disambiguated = disambiguated
+    self.was_ambiguous = was_ambiguous
+
+  def __str__(self):
+    return '%s [%s:%d]' % (
+        self.name or '??', self.source_path or '??', self.source_line or 0)
diff --git a/runtime/third_party/binary_size/src/explain_binary_size_delta.py b/runtime/third_party/binary_size/src/explain_binary_size_delta.py
new file mode 100755
index 0000000..45c1236
--- /dev/null
+++ b/runtime/third_party/binary_size/src/explain_binary_size_delta.py
@@ -0,0 +1,484 @@
+#!/usr/bin/env python
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Describe the size difference of two binaries.
+
+Generates a description of the size difference of two binaries based
+on the difference of the size of various symbols.
+
+This tool needs "nm" dumps of each binary with full symbol
+information. You can obtain the necessary dumps by running the
+run_binary_size_analysis.py script upon each binary, with the
+"--nm-out" parameter set to the location in which you want to save the
+dumps. Example:
+
+  # obtain symbol data from first binary in /tmp/nm1.dump
+  cd $CHECKOUT1_SRC
+  ninja -C out/Release binary_size_tool
+  tools/binary_size/run_binary_size_analysis \
+      --library <path_to_library>
+      --destdir /tmp/throwaway
+      --nm-out /tmp/nm1.dump
+
+  # obtain symbol data from second binary in /tmp/nm2.dump
+  cd $CHECKOUT2_SRC
+  ninja -C out/Release binary_size_tool
+  tools/binary_size/run_binary_size_analysis \
+      --library <path_to_library>
+      --destdir /tmp/throwaway
+      --nm-out /tmp/nm2.dump
+
+  # cleanup useless files
+  rm -r /tmp/throwaway
+
+  # run this tool
+  explain_binary_size_delta.py --nm1 /tmp/nm1.dump --nm2 /tmp/nm2.dump
+"""
+
+import collections
+from collections import Counter
+from math import ceil
+import operator
+import optparse
+import os
+import sys
+
+import binary_size_utils
+
+
+def CalculateSharedAddresses(symbols):
+  """Checks how many symbols share the same memory space. This returns a
+Counter result where result[address] will tell you how many times address was
+used by symbols."""
+  count = Counter()
+  for _, _, _, _, address in symbols:
+    count[address] += 1
+
+  return count
+
+
+def CalculateEffectiveSize(share_count, address, symbol_size):
+  """Given a raw symbol_size and an address, this method returns the
+  size we should blame on this symbol considering it might share the
+  machine code/data with other symbols. Using the raw symbol_size for
+  each symbol would in those cases over estimate the true cost of that
+  block.
+
+  """
+  shared_count = share_count[address]
+  if shared_count == 1:
+    return symbol_size
+
+  assert shared_count > 1
+  return int(ceil(symbol_size / float(shared_count)))
+
+class SymbolDelta(object):
+  """Stores old size, new size and some metadata."""
+  def __init__(self, shared):
+    self.old_size = None
+    self.new_size = None
+    self.shares_space_with_other_symbols = shared
+
+  def __eq__(self, other):
+    return (self.old_size == other.old_size and
+            self.new_size == other.new_size and
+            self.shares_space_with_other_symbols ==
+            other.shares_space_with_other_symbols)
+
+  def __ne__(self, other):
+    return not self.__eq__(other)
+
+  def copy_symbol_delta(self):
+    symbol_delta = SymbolDelta(self.shares_space_with_other_symbols)
+    symbol_delta.old_size = self.old_size
+    symbol_delta.new_size = self.new_size
+    return symbol_delta
+
+class DeltaInfo(SymbolDelta):
+  """Summary of a the change for one symbol between two instances."""
+  def __init__(self, file_path, symbol_type, symbol_name, shared):
+    SymbolDelta.__init__(self, shared)
+    self.file_path = file_path
+    self.symbol_type = symbol_type
+    self.symbol_name = symbol_name
+
+  def __eq__(self, other):
+    return (self.file_path == other.file_path and
+            self.symbol_type == other.symbol_type and
+            self.symbol_name == other.symbol_name and
+            SymbolDelta.__eq__(self, other))
+
+  def __ne__(self, other):
+    return not self.__eq__(other)
+
+  def ExtractSymbolDelta(self):
+    """Returns a copy of the SymbolDelta for this DeltaInfo."""
+    return SymbolDelta.copy_symbol_delta(self)
+
+def Compare(symbols1, symbols2):
+  """Executes a comparison of the symbols in symbols1 and symbols2.
+
+  Returns:
+      tuple of lists: (added_symbols, removed_symbols, changed_symbols, others)
+      where each list contains DeltaInfo objects.
+  """
+  added = [] # tuples
+  removed = [] # tuples
+  changed = [] # tuples
+  unchanged = [] # tuples
+
+  cache1 = {}
+  cache2 = {}
+  # Make a map of (file, symbol_type) : (symbol_name, effective_symbol_size)
+  share_count1 = CalculateSharedAddresses(symbols1)
+  share_count2 = CalculateSharedAddresses(symbols2)
+  for cache, symbols, share_count in ((cache1, symbols1, share_count1),
+                                      (cache2, symbols2, share_count2)):
+    for symbol_name, symbol_type, symbol_size, file_path, address in symbols:
+      if 'vtable for ' in symbol_name:
+        symbol_type = '@' # hack to categorize these separately
+      if file_path:
+        file_path = os.path.normpath(file_path)
+        if sys.platform.startswith('win'):
+          file_path = file_path.replace('\\', '/')
+      else:
+        file_path = '(No Path)'
+      # Take into consideration that multiple symbols might share the same
+      # block of code.
+      effective_symbol_size = CalculateEffectiveSize(share_count, address,
+                                                     symbol_size)
+      key = (file_path, symbol_type)
+      bucket = cache.setdefault(key, {})
+      size_list = bucket.setdefault(symbol_name, [])
+      size_list.append((effective_symbol_size,
+                        effective_symbol_size != symbol_size))
+
+  # Now diff them. We iterate over the elements in cache1. For each symbol
+  # that we find in cache2, we record whether it was deleted, changed, or
+  # unchanged. We then remove it from cache2; all the symbols that remain
+  # in cache2 at the end of the iteration over cache1 are the 'new' symbols.
+  for key, bucket1 in cache1.items():
+    bucket2 = cache2.get(key)
+    file_path, symbol_type = key;
+    if not bucket2:
+      # A file was removed. Everything in bucket1 is dead.
+      for symbol_name, symbol_size_list in bucket1.items():
+        for (symbol_size, shared) in symbol_size_list:
+          delta_info = DeltaInfo(file_path, symbol_type, symbol_name, shared)
+          delta_info.old_size = symbol_size
+          removed.append(delta_info)
+    else:
+      # File still exists, look for changes within.
+      for symbol_name, symbol_size_list in bucket1.items():
+        size_list2 = bucket2.get(symbol_name)
+        if size_list2 is None:
+          # Symbol no longer exists in bucket2.
+          for (symbol_size, shared) in symbol_size_list:
+            delta_info = DeltaInfo(file_path, symbol_type, symbol_name, shared)
+            delta_info.old_size = symbol_size
+            removed.append(delta_info)
+        else:
+          del bucket2[symbol_name] # Symbol is not new, delete from cache2.
+          if len(symbol_size_list) == 1 and len(size_list2) == 1:
+            symbol_size, shared1 = symbol_size_list[0]
+            size2, shared2 = size_list2[0]
+            delta_info = DeltaInfo(file_path, symbol_type, symbol_name,
+                                   shared1 or shared2)
+            delta_info.old_size = symbol_size
+            delta_info.new_size = size2
+            if symbol_size != size2:
+              # Symbol has change size in bucket.
+              changed.append(delta_info)
+            else:
+              # Symbol is unchanged.
+              unchanged.append(delta_info)
+          else:
+            # Complex comparison for when a symbol exists multiple times
+            # in the same file (where file can be "unknown file").
+            symbol_size_counter = collections.Counter(symbol_size_list)
+            delta_counter = collections.Counter(symbol_size_list)
+            delta_counter.subtract(size_list2)
+            for delta_counter_key in sorted(delta_counter.keys()):
+              delta = delta_counter[delta_counter_key]
+              unchanged_count = symbol_size_counter[delta_counter_key]
+              (symbol_size, shared) = delta_counter_key
+              if delta > 0:
+                unchanged_count -= delta
+              for _ in range(unchanged_count):
+                delta_info = DeltaInfo(file_path, symbol_type,
+                                       symbol_name, shared)
+                delta_info.old_size = symbol_size
+                delta_info.new_size = symbol_size
+                unchanged.append(delta_info)
+              if delta > 0: # Used to be more of these than there is now.
+                for _ in range(delta):
+                  delta_info = DeltaInfo(file_path, symbol_type,
+                                         symbol_name, shared)
+                  delta_info.old_size = symbol_size
+                  removed.append(delta_info)
+              elif delta < 0: # More of this (symbol,size) now.
+                for _ in range(-delta):
+                  delta_info = DeltaInfo(file_path, symbol_type,
+                                         symbol_name, shared)
+                  delta_info.new_size = symbol_size
+                  added.append(delta_info)
+
+          if len(bucket2) == 0:
+            del cache1[key] # Entire bucket is empty, delete from cache2
+
+  # We have now analyzed all symbols that are in cache1 and removed all of
+  # the encountered symbols from cache2. What's left in cache2 is the new
+  # symbols.
+  for key, bucket2 in cache2.iteritems():
+    file_path, symbol_type = key;
+    for symbol_name, symbol_size_list in bucket2.items():
+      for (symbol_size, shared) in symbol_size_list:
+        delta_info = DeltaInfo(file_path, symbol_type, symbol_name, shared)
+        delta_info.new_size = symbol_size
+        added.append(delta_info)
+  return (added, removed, changed, unchanged)
+
+
+def DeltaStr(number):
+  """Returns the number as a string with a '+' prefix if it's > 0 and
+  a '-' prefix if it's < 0."""
+  result = str(number)
+  if number > 0:
+    result = '+' + result
+  return result
+
+
+def SharedInfoStr(symbol_info):
+  """Returns a string (prefixed by space) explaining that numbers are
+  adjusted because of shared space between symbols, or an empty string
+  if space had not been shared."""
+
+  if symbol_info.shares_space_with_other_symbols:
+    return " (adjusted sizes because of memory sharing)"
+
+  return ""
+
+class CrunchStatsData(object):
+  """Stores a summary of data of a certain kind."""
+  def __init__(self, symbols):
+    self.symbols = symbols
+    self.sources = set()
+    self.before_size = 0
+    self.after_size = 0
+    self.symbols_by_path = {}
+
+
+def CrunchStats(added, removed, changed, unchanged, showsources, showsymbols):
+  """Outputs to stdout a summary of changes based on the symbol lists."""
+  # Split changed into grown and shrunk because that is easier to
+  # discuss.
+  grown = []
+  shrunk = []
+  for item in changed:
+    if item.old_size < item.new_size:
+      grown.append(item)
+    else:
+      shrunk.append(item)
+
+  new_symbols = CrunchStatsData(added)
+  removed_symbols = CrunchStatsData(removed)
+  grown_symbols = CrunchStatsData(grown)
+  shrunk_symbols = CrunchStatsData(shrunk)
+  sections = [new_symbols, removed_symbols, grown_symbols, shrunk_symbols]
+  for section in sections:
+    for item in section.symbols:
+      section.sources.add(item.file_path)
+      if item.old_size is not None:
+        section.before_size += item.old_size
+      if item.new_size is not None:
+        section.after_size += item.new_size
+      bucket = section.symbols_by_path.setdefault(item.file_path, [])
+      bucket.append((item.symbol_name, item.symbol_type,
+                     item.ExtractSymbolDelta()))
+
+  total_change = sum(s.after_size - s.before_size for s in sections)
+  summary = 'Total change: %s bytes' % DeltaStr(total_change)
+  print(summary)
+  print('=' * len(summary))
+  for section in sections:
+    if not section.symbols:
+      continue
+    if section.before_size == 0:
+      description = ('added, totalling %s bytes' % DeltaStr(section.after_size))
+    elif section.after_size == 0:
+      description = ('removed, totalling %s bytes' %
+                     DeltaStr(-section.before_size))
+    else:
+      if section.after_size > section.before_size:
+        type_str = 'grown'
+      else:
+        type_str = 'shrunk'
+      description = ('%s, for a net change of %s bytes '
+                     '(%d bytes before, %d bytes after)' %
+            (type_str, DeltaStr(section.after_size - section.before_size),
+             section.before_size, section.after_size))
+    print('  %d %s across %d sources' %
+          (len(section.symbols), description, len(section.sources)))
+
+  maybe_unchanged_sources = set()
+  unchanged_symbols_size = 0
+  for item in unchanged:
+    maybe_unchanged_sources.add(item.file_path)
+    unchanged_symbols_size += item.old_size # == item.new_size
+  print('  %d unchanged, totalling %d bytes' %
+        (len(unchanged), unchanged_symbols_size))
+
+  # High level analysis, always output.
+  unchanged_sources = maybe_unchanged_sources
+  for section in sections:
+    unchanged_sources = unchanged_sources - section.sources
+  new_sources = (new_symbols.sources -
+    maybe_unchanged_sources -
+    removed_symbols.sources)
+  removed_sources = (removed_symbols.sources -
+    maybe_unchanged_sources -
+    new_symbols.sources)
+  partially_changed_sources = (grown_symbols.sources |
+    shrunk_symbols.sources | new_symbols.sources |
+    removed_symbols.sources) - removed_sources - new_sources
+  allFiles = set()
+  for section in sections:
+    allFiles = allFiles | section.sources
+  allFiles = allFiles | maybe_unchanged_sources
+  print 'Source stats:'
+  print('  %d sources encountered.' % len(allFiles))
+  print('  %d completely new.' % len(new_sources))
+  print('  %d removed completely.' % len(removed_sources))
+  print('  %d partially changed.' % len(partially_changed_sources))
+  print('  %d completely unchanged.' % len(unchanged_sources))
+  remainder = (allFiles - new_sources - removed_sources -
+    partially_changed_sources - unchanged_sources)
+  assert len(remainder) == 0
+
+  if not showsources:
+    return  # Per-source analysis, only if requested
+  print 'Per-source Analysis:'
+  delta_by_path = {}
+  for section in sections:
+    for path in section.symbols_by_path:
+      entry = delta_by_path.get(path)
+      if not entry:
+        entry = {'plus': 0, 'minus': 0}
+        delta_by_path[path] = entry
+      for symbol_name, symbol_type, symbol_delta in \
+            section.symbols_by_path[path]:
+        if symbol_delta.old_size is None:
+          delta = symbol_delta.new_size
+        elif symbol_delta.new_size is None:
+          delta = -symbol_delta.old_size
+        else:
+          delta = symbol_delta.new_size - symbol_delta.old_size
+
+        if delta > 0:
+          entry['plus'] += delta
+        else:
+          entry['minus'] += (-1 * delta)
+
+  def delta_sort_key(item):
+    _path, size_data = item
+    growth = size_data['plus'] - size_data['minus']
+    return growth
+
+  for path, size_data in sorted(delta_by_path.iteritems(), key=delta_sort_key,
+                                reverse=True):
+    gain = size_data['plus']
+    loss = size_data['minus']
+    delta = size_data['plus'] - size_data['minus']
+    header = ' %s - Source: %s - (gained %d, lost %d)' % (DeltaStr(delta),
+                                                          path, gain, loss)
+    divider = '-' * len(header)
+    print ''
+    print divider
+    print header
+    print divider
+    if showsymbols:
+      def ExtractNewSize(tup):
+        symbol_delta = tup[2]
+        return symbol_delta.new_size
+      def ExtractOldSize(tup):
+        symbol_delta = tup[2]
+        return symbol_delta.old_size
+      if path in new_symbols.symbols_by_path:
+        print '  New symbols:'
+        for symbol_name, symbol_type, symbol_delta in \
+            sorted(new_symbols.symbols_by_path[path],
+                   key=ExtractNewSize,
+                   reverse=True):
+          print ('   %8s: %s type=%s, size=%d bytes%s' %
+                 (DeltaStr(symbol_delta.new_size), symbol_name, symbol_type,
+                  symbol_delta.new_size, SharedInfoStr(symbol_delta)))
+      if path in removed_symbols.symbols_by_path:
+        print '  Removed symbols:'
+        for symbol_name, symbol_type, symbol_delta in \
+            sorted(removed_symbols.symbols_by_path[path],
+                   key=ExtractOldSize):
+          print ('   %8s: %s type=%s, size=%d bytes%s' %
+                 (DeltaStr(-symbol_delta.old_size), symbol_name, symbol_type,
+                  symbol_delta.old_size,
+                  SharedInfoStr(symbol_delta)))
+      for (changed_symbols_by_path, type_str) in [
+        (grown_symbols.symbols_by_path, "Grown"),
+        (shrunk_symbols.symbols_by_path, "Shrunk")]:
+        if path in changed_symbols_by_path:
+          print '  %s symbols:' % type_str
+          def changed_symbol_sortkey(item):
+            symbol_name, _symbol_type, symbol_delta = item
+            return (symbol_delta.old_size - symbol_delta.new_size, symbol_name)
+          for symbol_name, symbol_type, symbol_delta in \
+              sorted(changed_symbols_by_path[path], key=changed_symbol_sortkey):
+            print ('   %8s: %s type=%s, (was %d bytes, now %d bytes)%s'
+                   % (DeltaStr(symbol_delta.new_size - symbol_delta.old_size),
+                      symbol_name, symbol_type,
+                      symbol_delta.old_size, symbol_delta.new_size,
+                      SharedInfoStr(symbol_delta)))
+
+
+def main():
+  usage = """%prog [options]
+
+  Analyzes the symbolic differences between two binary files
+  (typically, not necessarily, two different builds of the same
+  library) and produces a detailed description of symbols that have
+  been added, removed, or whose size has changed.
+
+  Example:
+       explain_binary_size_delta.py --nm1 /tmp/nm1.dump --nm2 /tmp/nm2.dump
+
+  Options are available via '--help'.
+  """
+  parser = optparse.OptionParser(usage=usage)
+  parser.add_option('--nm1', metavar='PATH',
+                    help='the nm dump of the first library')
+  parser.add_option('--nm2', metavar='PATH',
+                    help='the nm dump of the second library')
+  parser.add_option('--showsources', action='store_true', default=False,
+                    help='show per-source statistics')
+  parser.add_option('--showsymbols', action='store_true', default=False,
+                    help='show all symbol information; implies --showsources')
+  parser.add_option('--verbose', action='store_true', default=False,
+                    help='output internal debugging stuff')
+  opts, _args = parser.parse_args()
+
+  if not opts.nm1:
+    parser.error('--nm1 is required')
+  if not opts.nm2:
+    parser.error('--nm2 is required')
+  symbols = []
+  for path in [opts.nm1, opts.nm2]:
+    with file(path, 'r') as nm_input:
+      if opts.verbose:
+        print 'parsing ' + path + '...'
+      symbols.append(list(binary_size_utils.ParseNm(nm_input)))
+  (added, removed, changed, unchanged) = Compare(symbols[0], symbols[1])
+  CrunchStats(added, removed, changed, unchanged,
+    opts.showsources | opts.showsymbols, opts.showsymbols)
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/runtime/third_party/binary_size/src/run_binary_size_analysis.py b/runtime/third_party/binary_size/src/run_binary_size_analysis.py
new file mode 100755
index 0000000..d97858d
--- /dev/null
+++ b/runtime/third_party/binary_size/src/run_binary_size_analysis.py
@@ -0,0 +1,666 @@
+#!/usr/bin/env python
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Generate a spatial analysis against an arbitrary library.
+
+To use, build the 'binary_size_tool' target. Then run this tool, passing
+in the location of the library to be analyzed along with any other options
+you desire.
+"""
+
+import collections
+import json
+import logging
+import multiprocessing
+import optparse
+import os
+import re
+import shutil
+import struct
+import subprocess
+import sys
+import tempfile
+import time
+
+import binary_size_utils
+import elf_symbolizer
+
+# Node dictionary keys. These are output in json read by the webapp so
+# keep them short to save file size.
+# Note: If these change, the webapp must also change.
+NODE_TYPE_KEY = 'k'
+NODE_NAME_KEY = 'n'
+NODE_CHILDREN_KEY = 'children'
+NODE_SYMBOL_TYPE_KEY = 't'
+NODE_SYMBOL_SIZE_KEY = 'value'
+NODE_MAX_DEPTH_KEY = 'maxDepth'
+NODE_LAST_PATH_ELEMENT_KEY = 'lastPathElement'
+
+# The display name of the bucket where we put symbols without path.
+NAME_NO_PATH_BUCKET = '(No Path)'
+
+# Try to keep data buckets smaller than this to avoid killing the
+# graphing lib.
+BIG_BUCKET_LIMIT = 3000
+
+
+def _MkChild(node, name):
+  child = node[NODE_CHILDREN_KEY].get(name)
+  if child is None:
+    child = {NODE_NAME_KEY: name,
+             NODE_CHILDREN_KEY: {}}
+    node[NODE_CHILDREN_KEY][name] = child
+  return child
+
+
+
+def SplitNoPathBucket(node):
+  """NAME_NO_PATH_BUCKET can be too large for the graphing lib to
+  handle. Split it into sub-buckets in that case."""
+  root_children = node[NODE_CHILDREN_KEY]
+  if NAME_NO_PATH_BUCKET in root_children:
+    no_path_bucket = root_children[NAME_NO_PATH_BUCKET]
+    old_children = no_path_bucket[NODE_CHILDREN_KEY]
+    count = 0
+    for symbol_type, symbol_bucket in old_children.iteritems():
+      count += len(symbol_bucket[NODE_CHILDREN_KEY])
+    if count > BIG_BUCKET_LIMIT:
+      new_children = {}
+      no_path_bucket[NODE_CHILDREN_KEY] = new_children
+      current_bucket = None
+      index = 0
+      for symbol_type, symbol_bucket in old_children.iteritems():
+        for symbol_name, value in symbol_bucket[NODE_CHILDREN_KEY].iteritems():
+          if index % BIG_BUCKET_LIMIT == 0:
+            group_no = (index / BIG_BUCKET_LIMIT) + 1
+            current_bucket = _MkChild(no_path_bucket,
+                                      '%s subgroup %d' % (NAME_NO_PATH_BUCKET,
+                                                          group_no))
+            assert not NODE_TYPE_KEY in node or node[NODE_TYPE_KEY] == 'p'
+            node[NODE_TYPE_KEY] = 'p'  # p for path
+          index += 1
+          symbol_size = value[NODE_SYMBOL_SIZE_KEY]
+          AddSymbolIntoFileNode(current_bucket, symbol_type,
+                                symbol_name, symbol_size)
+
+
+def MakeChildrenDictsIntoLists(node):
+  largest_list_len = 0
+  if NODE_CHILDREN_KEY in node:
+    largest_list_len = len(node[NODE_CHILDREN_KEY])
+    child_list = []
+    for child in node[NODE_CHILDREN_KEY].itervalues():
+      child_largest_list_len = MakeChildrenDictsIntoLists(child)
+      if child_largest_list_len > largest_list_len:
+        largest_list_len = child_largest_list_len
+      child_list.append(child)
+    node[NODE_CHILDREN_KEY] = child_list
+
+  return largest_list_len
+
+
+def AddSymbolIntoFileNode(node, symbol_type, symbol_name, symbol_size):
+  """Puts symbol into the file path node |node|.
+  Returns the number of added levels in tree. I.e. returns 2."""
+
+  # 'node' is the file node and first step is to find its symbol-type bucket.
+  node[NODE_LAST_PATH_ELEMENT_KEY] = True
+  node = _MkChild(node, symbol_type)
+  assert not NODE_TYPE_KEY in node or node[NODE_TYPE_KEY] == 'b'
+  node[NODE_SYMBOL_TYPE_KEY] = symbol_type
+  node[NODE_TYPE_KEY] = 'b'  # b for bucket
+
+  # 'node' is now the symbol-type bucket. Make the child entry.
+  node = _MkChild(node, symbol_name)
+  if NODE_CHILDREN_KEY in node:
+    if node[NODE_CHILDREN_KEY]:
+      logging.warning('A container node used as symbol for %s.' % symbol_name)
+    # This is going to be used as a leaf so no use for child list.
+    del node[NODE_CHILDREN_KEY]
+  node[NODE_SYMBOL_SIZE_KEY] = symbol_size
+  node[NODE_SYMBOL_TYPE_KEY] = symbol_type
+  node[NODE_TYPE_KEY] = 's'  # s for symbol
+
+  return 2  # Depth of the added subtree.
+
+
+def MakeCompactTree(symbols, symbol_path_origin_dir):
+  result = {NODE_NAME_KEY: '/',
+            NODE_CHILDREN_KEY: {},
+            NODE_TYPE_KEY: 'p',
+            NODE_MAX_DEPTH_KEY: 0}
+  seen_symbol_with_path = False
+  cwd = os.path.abspath(os.getcwd())
+  for symbol_name, symbol_type, symbol_size, file_path, _address in symbols:
+
+    if 'vtable for ' in symbol_name:
+      symbol_type = '@'  # hack to categorize these separately
+    # Take path like '/foo/bar/baz', convert to ['foo', 'bar', 'baz']
+    if file_path and file_path != "??":
+      file_path = os.path.abspath(os.path.join(symbol_path_origin_dir,
+                                               file_path))
+      # Let the output structure be relative to $CWD if inside $CWD,
+      # otherwise relative to the disk root. This is to avoid
+      # unnecessary click-through levels in the output.
+      if file_path.startswith(cwd + os.sep):
+        file_path = file_path[len(cwd):]
+      if file_path.startswith('/'):
+        file_path = file_path[1:]
+      seen_symbol_with_path = True
+    else:
+      file_path = NAME_NO_PATH_BUCKET
+
+    path_parts = file_path.split('/')
+
+    # Find pre-existing node in tree, or update if it already exists
+    node = result
+    depth = 0
+    while len(path_parts) > 0:
+      path_part = path_parts.pop(0)
+      if len(path_part) == 0:
+        continue
+      depth += 1
+      node = _MkChild(node, path_part)
+      assert not NODE_TYPE_KEY in node or node[NODE_TYPE_KEY] == 'p'
+      node[NODE_TYPE_KEY] = 'p'  # p for path
+
+    depth += AddSymbolIntoFileNode(node, symbol_type, symbol_name, symbol_size)
+    result[NODE_MAX_DEPTH_KEY] = max(result[NODE_MAX_DEPTH_KEY], depth)
+
+  if not seen_symbol_with_path:
+    logging.warning('Symbols lack paths. Data will not be structured.')
+
+  # The (no path) bucket can be extremely large if we failed to get
+  # path information. Split it into subgroups if needed.
+  SplitNoPathBucket(result)
+
+  largest_list_len = MakeChildrenDictsIntoLists(result)
+
+  if largest_list_len > BIG_BUCKET_LIMIT:
+    logging.warning('There are sections with %d nodes. '
+                    'Results might be unusable.' % largest_list_len)
+  return result
+
+
+def DumpCompactTree(symbols, symbol_path_origin_dir, outfile):
+  tree_root = MakeCompactTree(symbols, symbol_path_origin_dir)
+  with open(outfile, 'w') as out:
+    out.write('var tree_data=')
+    # Use separators without whitespace to get a smaller file.
+    json.dump(tree_root, out, separators=(',', ':'))
+  print('Writing %d bytes json' % os.path.getsize(outfile))
+
+
+def MakeSourceMap(symbols):
+  sources = {}
+  for _sym, _symbol_type, size, path, _address in symbols:
+    key = None
+    if path:
+      key = os.path.normpath(path)
+    else:
+      key = '[no path]'
+    if key not in sources:
+      sources[key] = {'path': path, 'symbol_count': 0, 'size': 0}
+    record = sources[key]
+    record['size'] += size
+    record['symbol_count'] += 1
+  return sources
+
+
+# Regex for parsing "nm" output. A sample line looks like this:
+# 0167b39c 00000018 t ACCESS_DESCRIPTION_free /path/file.c:95
+#
+# The fields are: address, size, type, name, source location
+# Regular expression explained ( see also: https://xkcd.com/208 ):
+# ([0-9a-f]{8,}+)   The address
+# [\s]+             Whitespace separator
+# ([0-9a-f]{8,}+)   The size. From here on out it's all optional.
+# [\s]+             Whitespace separator
+# (\S?)             The symbol type, which is any non-whitespace char
+# [\s*]             Whitespace separator
+# ([^\t]*)          Symbol name, any non-tab character (spaces ok!)
+# [\t]?             Tab separator
+# (.*)              The location (filename[:linennum|?][ (discriminator n)]
+sNmPattern = re.compile(
+  r'([0-9a-f]{8,})[\s]+([0-9a-f]{8,})[\s]*(\S?)[\s*]([^\t]*)[\t]?(.*)')
+
+class Progress():
+  def __init__(self):
+    self.count = 0
+    self.skip_count = 0
+    self.collisions = 0
+    self.time_last_output = time.time()
+    self.count_last_output = 0
+    self.disambiguations = 0
+    self.was_ambiguous = 0
+
+
+def RunElfSymbolizer(outfile, library, addr2line_binary, nm_binary, jobs,
+                     disambiguate, src_path):
+  nm_output = RunNm(library, nm_binary)
+  nm_output_lines = nm_output.splitlines()
+  nm_output_lines_len = len(nm_output_lines)
+  address_symbol = {}
+  progress = Progress()
+  def map_address_symbol(symbol, addr):
+    progress.count += 1
+    if addr in address_symbol:
+      # 'Collision between %s and %s.' % (str(symbol.name),
+      #                                   str(address_symbol[addr].name))
+      progress.collisions += 1
+    else:
+      if symbol.disambiguated:
+        progress.disambiguations += 1
+      if symbol.was_ambiguous:
+        progress.was_ambiguous += 1
+
+      address_symbol[addr] = symbol
+
+    progress_output()
+
+  def progress_output():
+    progress_chunk = 100
+    if progress.count % progress_chunk == 0:
+      time_now = time.time()
+      time_spent = time_now - progress.time_last_output
+      if time_spent > 1.0:
+        # Only output at most once per second.
+        progress.time_last_output = time_now
+        chunk_size = progress.count - progress.count_last_output
+        progress.count_last_output = progress.count
+        if time_spent > 0:
+          speed = chunk_size / time_spent
+        else:
+          speed = 0
+        progress_percent = (100.0 * (progress.count + progress.skip_count) /
+                            nm_output_lines_len)
+        disambiguation_percent = 0
+        if progress.disambiguations != 0:
+          disambiguation_percent = (100.0 * progress.disambiguations /
+                                    progress.was_ambiguous)
+
+        sys.stdout.write('\r%.1f%%: Looked up %d symbols (%d collisions, '
+              '%d disambiguations where %.1f%% succeeded)'
+              ' - %.1f lookups/s.' %
+              (progress_percent, progress.count, progress.collisions,
+               progress.disambiguations, disambiguation_percent, speed))
+
+  # In case disambiguation was disabled, we remove the source path (which upon
+  # being set signals the symbolizer to enable disambiguation)
+  if not disambiguate:
+    src_path = None
+  symbolizer = elf_symbolizer.ELFSymbolizer(library, addr2line_binary,
+                                            map_address_symbol,
+                                            max_concurrent_jobs=jobs,
+                                            source_root_path=src_path)
+  user_interrupted = False
+  try:
+    for line in nm_output_lines:
+      match = sNmPattern.match(line)
+      if match:
+        location = match.group(5)
+        if not location:
+          addr = int(match.group(1), 16)
+          size = int(match.group(2), 16)
+          if addr in address_symbol:  # Already looked up, shortcut
+                                      # ELFSymbolizer.
+            map_address_symbol(address_symbol[addr], addr)
+            continue
+          elif size == 0:
+            # Save time by not looking up empty symbols (do they even exist?)
+            print('Empty symbol: ' + line)
+          else:
+            symbolizer.SymbolizeAsync(addr, addr)
+            continue
+
+      progress.skip_count += 1
+  except KeyboardInterrupt:
+    user_interrupted = True
+    print('Interrupting - killing subprocesses. Please wait.')
+
+  try:
+    symbolizer.Join()
+  except KeyboardInterrupt:
+    # Don't want to abort here since we will be finished in a few seconds.
+    user_interrupted = True
+    print('Patience you must have my young padawan.')
+
+  print ''
+
+  if user_interrupted:
+    print('Skipping the rest of the file mapping. '
+          'Output will not be fully classified.')
+
+  symbol_path_origin_dir = os.path.dirname(os.path.abspath(library))
+
+  with open(outfile, 'w') as out:
+    for line in nm_output_lines:
+      match = sNmPattern.match(line)
+      if match:
+        location = match.group(5)
+        if not location:
+          addr = int(match.group(1), 16)
+          symbol = address_symbol.get(addr)
+          if symbol is not None:
+            path = '??'
+            if symbol.source_path is not None:
+              path = os.path.abspath(os.path.join(symbol_path_origin_dir,
+                                                  symbol.source_path))
+            line_number = 0
+            if symbol.source_line is not None:
+              line_number = symbol.source_line
+            out.write('%s\t%s:%d\n' % (line, path, line_number))
+            continue
+
+      out.write('%s\n' % line)
+
+  print('%d symbols in the results.' % len(address_symbol))
+
+
+def RunNm(binary, nm_binary):
+  cmd = [nm_binary, '-C', '--print-size', '--size-sort', '--reverse-sort',
+         binary]
+  nm_process = subprocess.Popen(cmd,
+                                stdout=subprocess.PIPE,
+                                stderr=subprocess.PIPE)
+  (process_output, err_output) = nm_process.communicate()
+
+  if nm_process.returncode != 0:
+    if err_output:
+      raise Exception, err_output
+    else:
+      raise Exception, process_output
+
+  return process_output
+
+
+def GetNmSymbols(nm_infile, outfile, library, jobs, verbose,
+                 addr2line_binary, nm_binary, disambiguate, src_path):
+  if nm_infile is None:
+    if outfile is None:
+      outfile = tempfile.NamedTemporaryFile(delete=False).name
+
+    if verbose:
+      print 'Running parallel addr2line, dumping symbols to ' + outfile
+    RunElfSymbolizer(outfile, library, addr2line_binary, nm_binary, jobs,
+                     disambiguate, src_path)
+
+    nm_infile = outfile
+
+  elif verbose:
+    print 'Using nm input from ' + nm_infile
+  with file(nm_infile, 'r') as infile:
+    return list(binary_size_utils.ParseNm(infile))
+
+
+PAK_RESOURCE_ID_TO_STRING = { "inited": False }
+
+def LoadPakIdsFromResourceFile(filename):
+  """Given a file name, it loads everything that looks like a resource id
+  into PAK_RESOURCE_ID_TO_STRING."""
+  with open(filename) as resource_header:
+    for line in resource_header:
+      if line.startswith("#define "):
+        line_data = line.split()
+        if len(line_data) == 3:
+          try:
+            resource_number = int(line_data[2])
+            resource_name = line_data[1]
+            PAK_RESOURCE_ID_TO_STRING[resource_number] = resource_name
+          except ValueError:
+            pass
+
+def GetReadablePakResourceName(pak_file, resource_id):
+  """Pak resources have a numeric identifier. It is not helpful when
+  trying to locate where footprint is generated. This does its best to
+  map the number to a usable string."""
+  if not PAK_RESOURCE_ID_TO_STRING['inited']:
+    # Try to find resource header files generated by grit when
+    # building the pak file. We'll look for files named *resources.h"
+    # and lines of the type:
+    #    #define MY_RESOURCE_JS 1234
+    PAK_RESOURCE_ID_TO_STRING['inited'] = True
+    gen_dir = os.path.join(os.path.dirname(pak_file), 'gen')
+    if os.path.isdir(gen_dir):
+      for dirname, _dirs, files in os.walk(gen_dir):
+        for filename in files:
+          if filename.endswith('resources.h'):
+            LoadPakIdsFromResourceFile(os.path.join(dirname, filename))
+  return PAK_RESOURCE_ID_TO_STRING.get(resource_id,
+                                       'Pak Resource %d' % resource_id)
+
+def AddPakData(symbols, pak_file):
+  """Adds pseudo-symbols from a pak file."""
+  pak_file = os.path.abspath(pak_file)
+  with open(pak_file, 'rb') as pak:
+    data = pak.read()
+
+  PAK_FILE_VERSION = 4
+  HEADER_LENGTH = 2 * 4 + 1  # Two uint32s. (file version, number of entries)
+                             # and one uint8 (encoding of text resources)
+  INDEX_ENTRY_SIZE = 2 + 4  # Each entry is a uint16 and a uint32.
+  version, num_entries, _encoding = struct.unpack('<IIB', data[:HEADER_LENGTH])
+  assert version == PAK_FILE_VERSION, ('Unsupported pak file '
+                                       'version (%d) in %s. Only '
+                                       'support version %d' %
+                                       (version, pak_file, PAK_FILE_VERSION))
+  if num_entries > 0:
+    # Read the index and data.
+    data = data[HEADER_LENGTH:]
+    for _ in range(num_entries):
+      resource_id, offset = struct.unpack('<HI', data[:INDEX_ENTRY_SIZE])
+      data = data[INDEX_ENTRY_SIZE:]
+      _next_id, next_offset = struct.unpack('<HI', data[:INDEX_ENTRY_SIZE])
+      resource_size = next_offset - offset
+
+      symbol_name = GetReadablePakResourceName(pak_file, resource_id)
+      symbol_path = pak_file
+      symbol_type = 'd' # Data. Approximation.
+      symbol_size = resource_size
+      symbols.append((symbol_name, symbol_type, symbol_size, symbol_path))
+
+def _find_in_system_path(binary):
+  """Locate the full path to binary in the system path or return None
+  if not found."""
+  system_path = os.environ["PATH"].split(os.pathsep)
+  for path in system_path:
+    binary_path = os.path.join(path, binary)
+    if os.path.isfile(binary_path):
+      return binary_path
+  return None
+
+def CheckDebugFormatSupport(library, addr2line_binary):
+  """Kills the program if debug data is in an unsupported format.
+
+  There are two common versions of the DWARF debug formats and
+  since we are right now transitioning from DWARF2 to newer formats,
+  it's possible to have a mix of tools that are not compatible. Detect
+  that and abort rather than produce meaningless output."""
+  tool_output = subprocess.check_output([addr2line_binary, '--version'])
+  version_re = re.compile(r'^GNU [^ ]+ .* (\d+).(\d+).*?$', re.M)
+  parsed_output = version_re.match(tool_output)
+  major = int(parsed_output.group(1))
+  minor = int(parsed_output.group(2))
+  supports_dwarf4 = major > 2 or major == 2 and minor > 22
+
+  if supports_dwarf4:
+    return
+
+  print('Checking version of debug information in %s.' % library)
+  debug_info = subprocess.check_output(['readelf', '--debug-dump=info',
+                                       '--dwarf-depth=1', library])
+  dwarf_version_re = re.compile(r'^\s+Version:\s+(\d+)$', re.M)
+  parsed_dwarf_format_output = dwarf_version_re.search(debug_info)
+  version = int(parsed_dwarf_format_output.group(1))
+  if version > 2:
+    print('The supplied tools only support DWARF2 debug data but the binary\n' +
+          'uses DWARF%d. Update the tools or compile the binary\n' % version +
+          'with -gdwarf-2.')
+    sys.exit(1)
+
+
+def main():
+  usage = """%prog [options]
+
+  Runs a spatial analysis on a given library, looking up the source locations
+  of its symbols and calculating how much space each directory, source file,
+  and so on is taking. The result is a report that can be used to pinpoint
+  sources of large portions of the binary, etceteras.
+
+  Under normal circumstances, you only need to pass two arguments, thusly:
+
+      %prog --library /path/to/library --destdir /path/to/output
+
+  In this mode, the program will dump the symbols from the specified library
+  and map those symbols back to source locations, producing a web-based
+  report in the specified output directory.
+
+  Other options are available via '--help'.
+  """
+  parser = optparse.OptionParser(usage=usage)
+  parser.add_option('--nm-in', metavar='PATH',
+                    help='if specified, use nm input from <path> instead of '
+                    'generating it. Note that source locations should be '
+                    'present in the file; i.e., no addr2line symbol lookups '
+                    'will be performed when this option is specified. '
+                    'Mutually exclusive with --library.')
+  parser.add_option('--destdir', metavar='PATH',
+                    help='write output to the specified directory. An HTML '
+                    'report is generated here along with supporting files; '
+                    'any existing report will be overwritten.')
+  parser.add_option('--library', metavar='PATH',
+                    help='if specified, process symbols in the library at '
+                    'the specified path. Mutually exclusive with --nm-in.')
+  parser.add_option('--pak', metavar='PATH',
+                    help='if specified, includes the contents of the '
+                    'specified *.pak file in the output.')
+  parser.add_option('--nm-binary',
+                    help='use the specified nm binary to analyze library. '
+                    'This is to be used when the nm in the path is not for '
+                    'the right architecture or of the right version.')
+  parser.add_option('--addr2line-binary',
+                    help='use the specified addr2line binary to analyze '
+                    'library. This is to be used when the addr2line in '
+                    'the path is not for the right architecture or '
+                    'of the right version.')
+  parser.add_option('--jobs', type='int',
+                    help='number of jobs to use for the parallel '
+                    'addr2line processing pool; defaults to 1. More '
+                    'jobs greatly improve throughput but eat RAM like '
+                    'popcorn, and take several gigabytes each. Start low '
+                    'and ramp this number up until your machine begins to '
+                    'struggle with RAM. '
+                    'This argument is only valid when using --library.')
+  parser.add_option('-v', '--verbose', dest='verbose', action='store_true',
+                    help='be verbose, printing lots of status information.')
+  parser.add_option('--nm-out', metavar='PATH',
+                    help='(deprecated) No-op. nm.out is stored in --destdir.')
+  parser.add_option('--no-nm-out', action='store_true',
+                    help='do not keep the nm output file. This file is useful '
+                    'if you want to see the fully processed nm output after '
+                    'the symbols have been mapped to source locations, or if '
+                    'you plan to run explain_binary_size_delta.py. By default '
+                    'the file \'nm.out\' is placed alongside the generated '
+                    'report. The nm.out file is only created when using '
+                    '--library.')
+  parser.add_option('--disable-disambiguation', action='store_true',
+                    help='disables the disambiguation process altogether,'
+                    ' NOTE: this may, depending on your toolchain, produce'
+                    ' output with some symbols at the top layer if addr2line'
+                    ' could not get the entire source path.')
+  parser.add_option('--source-path', default='./',
+                    help='the path to the source code of the output binary, '
+                    'default set to current directory. Used in the'
+                    ' disambiguation process.')
+  opts, _args = parser.parse_args()
+
+  if ((not opts.library) and (not opts.nm_in)) or (opts.library and opts.nm_in):
+    parser.error('exactly one of --library or --nm-in is required')
+  if opts.nm_out:
+    print >> sys.stderr, ('WARNING: --nm-out is deprecated and has no effect.')
+  if (opts.nm_in):
+    if opts.jobs:
+      print >> sys.stderr, ('WARNING: --jobs has no effect '
+                            'when used with --nm-in')
+  if not opts.destdir:
+    parser.error('--destdir is a required argument')
+  if not opts.jobs:
+    # Use the number of processors but cap between 2 and 4 since raw
+    # CPU power isn't the limiting factor. It's I/O limited, memory
+    # bus limited and available-memory-limited. Too many processes and
+    # the computer will run out of memory and it will be slow.
+    opts.jobs = max(2, min(4, str(multiprocessing.cpu_count())))
+
+  if opts.addr2line_binary:
+    assert os.path.isfile(opts.addr2line_binary)
+    addr2line_binary = opts.addr2line_binary
+  else:
+    addr2line_binary = _find_in_system_path('addr2line')
+    assert addr2line_binary, 'Unable to find addr2line in the path. '\
+        'Use --addr2line-binary to specify location.'
+
+  if opts.nm_binary:
+    assert os.path.isfile(opts.nm_binary)
+    nm_binary = opts.nm_binary
+  else:
+    nm_binary = _find_in_system_path('nm')
+    assert nm_binary, 'Unable to find nm in the path. Use --nm-binary '\
+        'to specify location.'
+
+  if opts.pak:
+    assert os.path.isfile(opts.pak), 'Could not find ' % opts.pak
+
+  print('addr2line: %s' % addr2line_binary)
+  print('nm: %s' % nm_binary)
+
+  if opts.library:
+    CheckDebugFormatSupport(opts.library, addr2line_binary)
+
+  # Prepare output directory and report guts
+  if not os.path.exists(opts.destdir):
+    os.makedirs(opts.destdir, 0755)
+  nm_out = os.path.join(opts.destdir, 'nm.out')
+  if opts.no_nm_out:
+    nm_out = None
+
+  # Copy report boilerplate into output directory. This also proves that the
+  # output directory is safe for writing, so there should be no problems writing
+  # the nm.out file later.
+  data_js_file_name = os.path.join(opts.destdir, 'data.js')
+  d3_out = os.path.join(opts.destdir, 'd3')
+  if not os.path.exists(d3_out):
+    os.makedirs(d3_out, 0755)
+  d3_src = os.path.join(os.path.dirname(__file__),
+                        '..',
+                        '..',
+                        'd3', 'src')
+  template_src = os.path.join(os.path.dirname(__file__),
+                              'template')
+  shutil.copy(os.path.join(d3_src, 'LICENSE'), d3_out)
+  shutil.copy(os.path.join(d3_src, 'd3.js'), d3_out)
+  shutil.copy(os.path.join(template_src, 'index.html'), opts.destdir)
+  shutil.copy(os.path.join(template_src, 'D3SymbolTreeMap.js'), opts.destdir)
+
+  # Run nm and/or addr2line to gather the data
+  symbols = GetNmSymbols(opts.nm_in, nm_out, opts.library,
+                         opts.jobs, opts.verbose is True,
+                         addr2line_binary, nm_binary,
+                         opts.disable_disambiguation is None,
+                         opts.source_path)
+
+  # Post-processing
+  if opts.pak:
+    AddPakData(symbols, opts.pak)
+  if opts.library:
+    symbol_path_origin_dir = os.path.dirname(os.path.abspath(opts.library))
+  else:
+    # Just a guess. Hopefully all paths in the input file are absolute.
+    symbol_path_origin_dir = os.path.abspath(os.getcwd())
+  # Dump JSON for the HTML report.
+  DumpCompactTree(symbols, symbol_path_origin_dir, data_js_file_name)
+  print 'Report saved to ' + opts.destdir + '/index.html'
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/runtime/third_party/binary_size/src/template/D3SymbolTreeMap.js b/runtime/third_party/binary_size/src/template/D3SymbolTreeMap.js
new file mode 100644
index 0000000..4bbe82f
--- /dev/null
+++ b/runtime/third_party/binary_size/src/template/D3SymbolTreeMap.js
@@ -0,0 +1,938 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// TODO:
+// 1. Visibility functions: base on boxPadding.t, not 15
+// 2. Track a maxDisplayDepth that is user-settable:
+//    maxDepth == currentRoot.depth + maxDisplayDepth
+function D3SymbolTreeMap(mapWidth, mapHeight, levelsToShow) {
+  this._mapContainer = undefined;
+  this._mapWidth = mapWidth;
+  this._mapHeight = mapHeight;
+  this.boxPadding = {'l': 5, 'r': 5, 't': 20, 'b': 5};
+  this.infobox = undefined;
+  this._maskContainer = undefined;
+  this._highlightContainer = undefined;
+  // Transition in this order:
+  // 1. Exiting items go away.
+  // 2. Updated items move.
+  // 3. New items enter.
+  this._exitDuration=500;
+  this._updateDuration=500;
+  this._enterDuration=500;
+  this._firstTransition=true;
+  this._layout = undefined;
+  this._currentRoot = undefined;
+  this._currentNodes = undefined;
+  this._treeData = undefined;
+  this._maxLevelsToShow = levelsToShow;
+  this._currentMaxDepth = this._maxLevelsToShow;
+}
+
+/**
+ * Make a number pretty, with comma separators.
+ */
+D3SymbolTreeMap._pretty = function(num) {
+  var asString = String(num);
+  var result = '';
+  var counter = 0;
+  for (var x = asString.length - 1; x >= 0; x--) {
+    counter++;
+    if (counter === 4) {
+      result = ',' + result;
+      counter = 1;
+    }
+    result = asString.charAt(x) + result;
+  }
+  return result;
+}
+
+/**
+ * Express a number in terms of KiB, MiB, GiB, etc.
+ * Note that these are powers of 2, not of 10.
+ */
+D3SymbolTreeMap._byteify = function(num) {
+  var suffix;
+  if (num >= 1024) {
+    if (num >= 1024 * 1024 * 1024) {
+      suffix = 'GiB';
+      num = num / (1024 * 1024 * 1024);
+    } else if (num >= 1024 * 1024) {
+      suffix = 'MiB';
+      num = num / (1024 * 1024);
+    } else if (num >= 1024) {
+      suffix = 'KiB'
+      num = num / 1024;
+    }
+    return num.toFixed(2) + ' ' + suffix;
+  }
+  return num + ' B';
+}
+
+D3SymbolTreeMap._NM_SYMBOL_TYPE_DESCRIPTIONS = {
+  // Definitions concisely derived from the nm 'man' page
+  'A': 'Global absolute (A)',
+  'B': 'Global uninitialized data (B)',
+  'b': 'Local uninitialized data (b)',
+  'C': 'Global uninitialized common (C)',
+  'D': 'Global initialized data (D)',
+  'd': 'Local initialized data (d)',
+  'G': 'Global small initialized data (G)',
+  'g': 'Local small initialized data (g)',
+  'i': 'Indirect function (i)',
+  'N': 'Debugging (N)',
+  'p': 'Stack unwind (p)',
+  'R': 'Global read-only data (R)',
+  'r': 'Local read-only data (r)',
+  'S': 'Global small uninitialized data (S)',
+  's': 'Local small uninitialized data (s)',
+  'T': 'Global code (T)',
+  't': 'Local code (t)',
+  'U': 'Undefined (U)',
+  'u': 'Unique (u)',
+  'V': 'Global weak object (V)',
+  'v': 'Local weak object (v)',
+  'W': 'Global weak symbol (W)',
+  'w': 'Local weak symbol (w)',
+  '@': 'Vtable entry (@)', // non-standard, hack.
+  '-': 'STABS debugging (-)',
+  '?': 'Unrecognized (?)',
+};
+D3SymbolTreeMap._NM_SYMBOL_TYPES = '';
+for (var symbol_type in D3SymbolTreeMap._NM_SYMBOL_TYPE_DESCRIPTIONS) {
+  D3SymbolTreeMap._NM_SYMBOL_TYPES += symbol_type;
+}
+
+/**
+ * Given a symbol type code, look up and return a human-readable description
+ * of that symbol type. If the symbol type does not match one of the known
+ * types, the unrecognized description (corresponding to symbol type '?') is
+ * returned instead of null or undefined.
+ */
+D3SymbolTreeMap._getSymbolDescription = function(type) {
+  var result = D3SymbolTreeMap._NM_SYMBOL_TYPE_DESCRIPTIONS[type];
+  if (result === undefined) {
+    result = D3SymbolTreeMap._NM_SYMBOL_TYPE_DESCRIPTIONS['?'];
+  }
+  return result;
+}
+
+// Qualitative 12-value pastel Brewer palette.
+D3SymbolTreeMap._colorArray = [
+  'rgb(141,211,199)',
+  'rgb(255,255,179)',
+  'rgb(190,186,218)',
+  'rgb(251,128,114)',
+  'rgb(128,177,211)',
+  'rgb(253,180,98)',
+  'rgb(179,222,105)',
+  'rgb(252,205,229)',
+  'rgb(217,217,217)',
+  'rgb(188,128,189)',
+  'rgb(204,235,197)',
+  'rgb(255,237,111)'];
+
+D3SymbolTreeMap._initColorMap = function() {
+  var map = {};
+  var numColors = D3SymbolTreeMap._colorArray.length;
+  var count = 0;
+  for (var key in D3SymbolTreeMap._NM_SYMBOL_TYPE_DESCRIPTIONS) {
+    var index = count++ % numColors;
+    map[key] = d3.rgb(D3SymbolTreeMap._colorArray[index]);
+  }
+  D3SymbolTreeMap._colorMap = map;
+}
+D3SymbolTreeMap._initColorMap();
+
+D3SymbolTreeMap.getColorForType = function(type) {
+  var result = D3SymbolTreeMap._colorMap[type];
+  if (result === undefined) return d3.rgb('rgb(255,255,255)');
+  return result;
+}
+
+D3SymbolTreeMap.prototype.init = function() {
+  this.infobox = this._createInfoBox();
+  this._mapContainer = d3.select('body').append('div')
+      .style('position', 'relative')
+      .style('width', this._mapWidth)
+      .style('height', this._mapHeight)
+      .style('padding', 0)
+      .style('margin', 0)
+      .style('box-shadow', '5px 5px 5px #888');
+  this._layout = this._createTreeMapLayout();
+  this._setData(tree_data); // TODO: Don't use global 'tree_data'
+}
+
+/**
+ * Sets the data displayed by the treemap and layint out the map.
+ */
+D3SymbolTreeMap.prototype._setData = function(data) {
+  this._treeData = data;
+  console.time('_crunchStats');
+  this._crunchStats(data);
+  console.timeEnd('_crunchStats');
+  this._currentRoot = this._treeData;
+  this._currentNodes = this._layout.nodes(this._currentRoot);
+  this._currentMaxDepth = this._maxLevelsToShow;
+  this._doLayout();
+}
+
+/**
+ * Recursively traverses the entire tree starting from the specified node,
+ * computing statistics and recording metadata as it goes. Call this method
+ * only once per imported tree.
+ */
+D3SymbolTreeMap.prototype._crunchStats = function(node) {
+  var stack = [];
+  stack.idCounter = 0;
+  this._crunchStatsHelper(stack, node);
+}
+
+/**
+ * Invoke the specified visitor function on all data elements currently shown
+ * in the treemap including any and all of their children, starting at the
+ * currently-displayed root and descening recursively. The function will be
+ * passed the datum element representing each node. No traversal guarantees
+ * are made.
+ */
+D3SymbolTreeMap.prototype.visitFromDisplayedRoot = function(visitor) {
+  this._visit(this._currentRoot, visitor);
+}
+
+/**
+ * Helper function for visit functions.
+ */
+D3SymbolTreeMap.prototype._visit = function(datum, visitor) {
+  visitor.call(this, datum);
+  if (datum.children) for (var i = 0; i < datum.children.length; i++) {
+    this._visit(datum.children[i], visitor);
+  }
+}
+
+D3SymbolTreeMap.prototype._crunchStatsHelper = function(stack, node) {
+  // Only overwrite the node ID if it isn't already set.
+  // This allows stats to be crunched multiple times on subsets of data
+  // without breaking the data-to-ID bindings. New nodes get new IDs.
+  if (node.id === undefined) node.id = stack.idCounter++;
+  if (node.children === undefined) {
+    // Leaf node (symbol); accumulate stats.
+    for (var i = 0; i < stack.length; i++) {
+      var ancestor = stack[i];
+      if (!ancestor.symbol_stats) ancestor.symbol_stats = {};
+      if (ancestor.symbol_stats[node.t] === undefined) {
+        // New symbol type we haven't seen before, just record.
+        ancestor.symbol_stats[node.t] = {'count': 1,
+                                         'size': node.value};
+      } else {
+        // Existing symbol type, increment.
+        ancestor.symbol_stats[node.t].count++;
+        ancestor.symbol_stats[node.t].size += node.value;
+      }
+    }
+  } else for (var i = 0; i < node.children.length; i++) {
+    stack.push(node);
+    this._crunchStatsHelper(stack, node.children[i]);
+    stack.pop();
+  }
+}
+
+D3SymbolTreeMap.prototype._createTreeMapLayout = function() {
+  var result = d3.layout.treemap()
+      .padding([this.boxPadding.t, this.boxPadding.r,
+                this.boxPadding.b, this.boxPadding.l])
+      .size([this._mapWidth, this._mapHeight]);
+  return result;
+}
+
+D3SymbolTreeMap.prototype.resize = function(width, height) {
+  this._mapWidth = width;
+  this._mapHeight = height;
+  this._mapContainer.style('width', width).style('height', height);
+  this._layout.size([this._mapWidth, this._mapHeight]);
+  this._currentNodes = this._layout.nodes(this._currentRoot);
+  this._doLayout();
+}
+
+D3SymbolTreeMap.prototype._zoomDatum = function(datum) {
+  if (this._currentRoot === datum) return; // already here
+  this._hideHighlight(datum);
+  this._hideInfoBox(datum);
+  this._currentRoot = datum;
+  this._currentNodes = this._layout.nodes(this._currentRoot);
+  this._currentMaxDepth = this._currentRoot.depth + this._maxLevelsToShow;
+  console.log('zooming into datum ' + this._currentRoot.n);
+  this._doLayout();
+}
+
+D3SymbolTreeMap.prototype.setMaxLevels = function(levelsToShow) {
+  this._maxLevelsToShow = levelsToShow;
+  this._currentNodes = this._layout.nodes(this._currentRoot);
+  this._currentMaxDepth = this._currentRoot.depth + this._maxLevelsToShow;
+  console.log('setting max levels to show: ' + this._maxLevelsToShow);
+  this._doLayout();
+}
+
+/**
+ * Clone the specified tree, returning an independent copy of the data.
+ * Only the original attributes expected to exist prior to invoking
+ * _crunchStatsHelper are retained, with the exception of the 'id' attribute
+ * (which must be retained for proper transitions).
+ * If the optional filter parameter is provided, it will be called with 'this'
+ * set to this treemap instance and passed the 'datum' object as an argument.
+ * When specified, the copy will retain only the data for which the filter
+ * function returns true.
+ */
+D3SymbolTreeMap.prototype._clone = function(datum, filter) {
+  var trackingStats = false;
+  if (this.__cloneState === undefined) {
+    console.time('_clone');
+    trackingStats = true;
+    this.__cloneState = {'accepted': 0, 'rejected': 0,
+                         'forced': 0, 'pruned': 0};
+  }
+
+  // Must go depth-first. All parents of children that are accepted by the
+  // filter must be preserved!
+  var copy = {'n': datum.n, 'k': datum.k};
+  var childAccepted = false;
+  if (datum.children !== undefined) {
+    for (var i = 0; i < datum.children.length; i++) {
+      var copiedChild = this._clone(datum.children[i], filter);
+      if (copiedChild !== undefined) {
+        childAccepted = true; // parent must also be accepted.
+        if (copy.children === undefined) copy.children = [];
+        copy.children.push(copiedChild);
+      }
+    }
+  }
+
+  // Ignore nodes that don't match the filter, when present.
+  var accept = false;
+  if (childAccepted) {
+    // Parent of an accepted child must also be accepted.
+    this.__cloneState.forced++;
+    accept = true;
+  } else if (filter !== undefined && filter.call(this, datum) !== true) {
+    this.__cloneState.rejected++;
+  } else if (datum.children === undefined) {
+    // Accept leaf nodes that passed the filter
+    this.__cloneState.accepted++;
+    accept = true;
+  } else {
+    // Non-leaf node. If no children are accepted, prune it.
+    this.__cloneState.pruned++;
+  }
+
+  if (accept) {
+    if (datum.id !== undefined) copy.id = datum.id;
+    if (datum.lastPathElement !== undefined) {
+      copy.lastPathElement = datum.lastPathElement;
+    }
+    if (datum.t !== undefined) copy.t = datum.t;
+    if (datum.value !== undefined && datum.children === undefined) {
+      copy.value = datum.value;
+    }
+  } else {
+    // Discard the copy we were going to return
+    copy = undefined;
+  }
+
+  if (trackingStats === true) {
+    // We are the fist call in the recursive chain.
+    console.timeEnd('_clone');
+    var totalAccepted = this.__cloneState.accepted +
+                        this.__cloneState.forced;
+    console.log(
+        totalAccepted + ' nodes retained (' +
+        this.__cloneState.forced + ' forced by accepted children, ' +
+        this.__cloneState.accepted + ' accepted on their own merits), ' +
+        this.__cloneState.rejected + ' nodes (and their children) ' +
+                                     'filtered out,' +
+        this.__cloneState.pruned + ' nodes pruned because because no ' +
+                                   'children remained.');
+    delete this.__cloneState;
+  }
+  return copy;
+}
+
+D3SymbolTreeMap.prototype.filter = function(filter) {
+  // Ensure we have a copy of the original root.
+  if (this._backupTree === undefined) this._backupTree = this._treeData;
+  this._mapContainer.selectAll('div').remove();
+  this._setData(this._clone(this._backupTree, filter));
+}
+
+D3SymbolTreeMap.prototype._doLayout = function() {
+  console.time('_doLayout');
+  this._handleInodes();
+  this._handleLeaves();
+  this._firstTransition = false;
+  console.timeEnd('_doLayout');
+}
+
+D3SymbolTreeMap.prototype._highlightElement = function(datum, selection) {
+  this._showHighlight(datum, selection);
+}
+
+D3SymbolTreeMap.prototype._unhighlightElement = function(datum, selection) {
+  this._hideHighlight(datum, selection);
+}
+
+D3SymbolTreeMap.prototype._handleInodes = function() {
+  console.time('_handleInodes');
+  var thisTreeMap = this;
+  var inodes = this._currentNodes.filter(function(datum){
+    return (datum.depth <= thisTreeMap._currentMaxDepth) &&
+            datum.children !== undefined;
+  });
+  var cellsEnter = this._mapContainer.selectAll('div.inode')
+      .data(inodes, function(datum) { return datum.id; })
+      .enter()
+      .append('div').attr('class', 'inode').attr('id', function(datum){
+          return 'node-' + datum.id;});
+
+
+  // Define enter/update/exit for inodes
+  cellsEnter
+      .append('div')
+      .attr('class', 'rect inode_rect_entering')
+      .style('z-index', function(datum) { return datum.id * 2; })
+      .style('position', 'absolute')
+      .style('left', function(datum) { return datum.x; })
+      .style('top', function(datum){ return datum.y; })
+      .style('width', function(datum){ return datum.dx; })
+      .style('height', function(datum){ return datum.dy; })
+      .style('opacity', '0')
+      .style('border', '1px solid black')
+      .style('background-image', function(datum) {
+        return thisTreeMap._makeSymbolBucketBackgroundImage.call(
+               thisTreeMap, datum);
+      })
+      .style('background-color', function(datum) {
+        if (datum.t === undefined) return 'rgb(220,220,220)';
+        return D3SymbolTreeMap.getColorForType(datum.t).toString();
+      })
+      .on('mouseover', function(datum){
+        thisTreeMap._highlightElement.call(
+            thisTreeMap, datum, d3.select(this));
+        thisTreeMap._showInfoBox.call(thisTreeMap, datum);
+      })
+      .on('mouseout', function(datum){
+        thisTreeMap._unhighlightElement.call(
+            thisTreeMap, datum, d3.select(this));
+        thisTreeMap._hideInfoBox.call(thisTreeMap, datum);
+      })
+      .on('mousemove', function(){
+          thisTreeMap._moveInfoBox.call(thisTreeMap, event);
+      })
+      .on('dblclick', function(datum){
+        if (datum !== thisTreeMap._currentRoot) {
+          // Zoom into the selection
+          thisTreeMap._zoomDatum(datum);
+        } else if (datum.parent) {
+          console.log('event.shiftKey=' + event.shiftKey);
+          if (event.shiftKey === true) {
+            // Back to root
+            thisTreeMap._zoomDatum(thisTreeMap._treeData);
+          } else {
+            // Zoom out of the selection
+            thisTreeMap._zoomDatum(datum.parent);
+          }
+        }
+      });
+  cellsEnter
+      .append('div')
+      .attr('class', 'label inode_label_entering')
+      .style('z-index', function(datum) { return (datum.id * 2) + 1; })
+      .style('position', 'absolute')
+      .style('left', function(datum){ return datum.x; })
+      .style('top', function(datum){ return datum.y; })
+      .style('width', function(datum) { return datum.dx; })
+      .style('height', function(datum) { return thisTreeMap.boxPadding.t; })
+      .style('opacity', '0')
+      .style('pointer-events', 'none')
+      .style('-webkit-user-select', 'none')
+      .style('overflow', 'hidden') // required for ellipsis
+      .style('white-space', 'nowrap') // required for ellipsis
+      .style('text-overflow', 'ellipsis')
+      .style('text-align', 'center')
+      .style('vertical-align', 'top')
+      .style('visibility', function(datum) {
+        return (datum.dx < 15 || datum.dy < 15) ? 'hidden' : 'visible';
+      })
+      .text(function(datum) {
+        var sizeish = ' [' + D3SymbolTreeMap._byteify(datum.value) + ']'
+        var text;
+        if (datum.k === 'b') { // bucket
+          if (datum === thisTreeMap._currentRoot) {
+            text = thisTreeMap.pathFor(datum) + ': '
+                + D3SymbolTreeMap._getSymbolDescription(datum.t)
+          } else {
+            text = D3SymbolTreeMap._getSymbolDescription(datum.t);
+          }
+        } else if (datum === thisTreeMap._currentRoot) {
+          // The top-most level should always show the complete path
+          text = thisTreeMap.pathFor(datum);
+        } else {
+          // Anything that isn't a bucket or a leaf (symbol) or the
+          // current root should just show its name.
+          text = datum.n;
+        }
+        return text + sizeish;
+      }
+  );
+
+  // Complicated transition logic:
+  // For nodes that are entering, we want to fade them in in-place AFTER
+  // any adjusting nodes have resized and moved around. That way, new nodes
+  // seamlessly appear in the right spot after their containers have resized
+  // and moved around.
+  // To do this we do some trickery:
+  // 1. Define a '_entering' class on the entering elements
+  // 2. Use this to select only the entering elements and apply the opacity
+  //    transition.
+  // 3. Use the same transition to drop the '_entering' suffix, so that they
+  //    will correctly update in later zoom/resize/whatever operations.
+  // 4. The update transition is achieved by selecting the elements without
+  //    the '_entering_' suffix and applying movement and resizing transition
+  //    effects.
+  this._mapContainer.selectAll('div.inode_rect_entering').transition()
+      .duration(thisTreeMap._enterDuration).delay(
+          this._firstTransition ? 0 : thisTreeMap._exitDuration +
+              thisTreeMap._updateDuration)
+      .attr('class', 'rect inode_rect')
+      .style('opacity', '1')
+  this._mapContainer.selectAll('div.inode_label_entering').transition()
+      .duration(thisTreeMap._enterDuration).delay(
+          this._firstTransition ? 0 : thisTreeMap._exitDuration +
+              thisTreeMap._updateDuration)
+      .attr('class', 'label inode_label')
+      .style('opacity', '1')
+  this._mapContainer.selectAll('div.inode_rect').transition()
+      .duration(thisTreeMap._updateDuration).delay(thisTreeMap._exitDuration)
+      .style('opacity', '1')
+      .style('background-image', function(datum) {
+        return thisTreeMap._makeSymbolBucketBackgroundImage.call(
+            thisTreeMap, datum);
+      })
+      .style('left', function(datum) { return datum.x; })
+      .style('top', function(datum){ return datum.y; })
+      .style('width', function(datum){ return datum.dx; })
+      .style('height', function(datum){ return datum.dy; });
+  this._mapContainer.selectAll('div.inode_label').transition()
+      .duration(thisTreeMap._updateDuration).delay(thisTreeMap._exitDuration)
+      .style('opacity', '1')
+      .style('visibility', function(datum) {
+        return (datum.dx < 15 || datum.dy < 15) ? 'hidden' : 'visible';
+      })
+      .style('left', function(datum){ return datum.x; })
+      .style('top', function(datum){ return datum.y; })
+      .style('width', function(datum) { return datum.dx; })
+      .style('height', function(datum) { return thisTreeMap.boxPadding.t; })
+      .text(function(datum) {
+        var sizeish = ' [' + D3SymbolTreeMap._byteify(datum.value) + ']'
+        var text;
+        if (datum.k === 'b') {
+          if (datum === thisTreeMap._currentRoot) {
+            text = thisTreeMap.pathFor(datum) + ': ' +
+                D3SymbolTreeMap._getSymbolDescription(datum.t)
+          } else {
+            text = D3SymbolTreeMap._getSymbolDescription(datum.t);
+          }
+        } else if (datum === thisTreeMap._currentRoot) {
+          // The top-most level should always show the complete path
+          text = thisTreeMap.pathFor(datum);
+        } else {
+          // Anything that isn't a bucket or a leaf (symbol) or the
+          // current root should just show its name.
+          text = datum.n;
+        }
+        return text + sizeish;
+      });
+  var exit = this._mapContainer.selectAll('div.inode')
+      .data(inodes, function(datum) { return 'inode-' + datum.id; })
+      .exit();
+  exit.selectAll('div.inode_rect').transition().duration(
+      thisTreeMap._exitDuration).style('opacity', 0);
+  exit.selectAll('div.inode_label').transition().duration(
+      thisTreeMap._exitDuration).style('opacity', 0);
+  exit.transition().delay(thisTreeMap._exitDuration + 1).remove();
+
+  console.log(inodes.length + ' inodes layed out.');
+  console.timeEnd('_handleInodes');
+}
+
+D3SymbolTreeMap.prototype._handleLeaves = function() {
+  console.time('_handleLeaves');
+  var color_fn = d3.scale.category10();
+  var thisTreeMap = this;
+  var leaves = this._currentNodes.filter(function(datum){
+    return (datum.depth <= thisTreeMap._currentMaxDepth) &&
+        datum.children === undefined; });
+  var cellsEnter = this._mapContainer.selectAll('div.leaf')
+      .data(leaves, function(datum) { return datum.id; })
+      .enter()
+      .append('div').attr('class', 'leaf').attr('id', function(datum){
+        return 'node-' + datum.id;
+      });
+
+  // Define enter/update/exit for leaves
+  cellsEnter
+      .append('div')
+      .attr('class', 'rect leaf_rect_entering')
+      .style('z-index', function(datum) { return datum.id * 2; })
+      .style('position', 'absolute')
+      .style('left', function(datum){ return datum.x; })
+      .style('top', function(datum){ return datum.y; })
+      .style('width', function(datum){ return datum.dx; })
+      .style('height', function(datum){ return datum.dy; })
+      .style('opacity', '0')
+      .style('background-color', function(datum) {
+        if (datum.t === undefined) return 'rgb(220,220,220)';
+        return D3SymbolTreeMap.getColorForType(datum.t)
+            .darker(0.3).toString();
+      })
+      .style('border', '1px solid black')
+      .on('mouseover', function(datum){
+        thisTreeMap._highlightElement.call(
+            thisTreeMap, datum, d3.select(this));
+        thisTreeMap._showInfoBox.call(thisTreeMap, datum);
+      })
+      .on('mouseout', function(datum){
+        thisTreeMap._unhighlightElement.call(
+            thisTreeMap, datum, d3.select(this));
+        thisTreeMap._hideInfoBox.call(thisTreeMap, datum);
+      })
+      .on('mousemove', function(){ thisTreeMap._moveInfoBox.call(
+        thisTreeMap, event);
+      });
+  cellsEnter
+      .append('div')
+      .attr('class', 'label leaf_label_entering')
+      .style('z-index', function(datum) { return (datum.id * 2) + 1; })
+      .style('position', 'absolute')
+      .style('left', function(datum){ return datum.x; })
+      .style('top', function(datum){ return datum.y; })
+      .style('width', function(datum) { return datum.dx; })
+      .style('height', function(datum) { return datum.dy; })
+      .style('opacity', '0')
+      .style('pointer-events', 'none')
+      .style('-webkit-user-select', 'none')
+      .style('overflow', 'hidden') // required for ellipsis
+      .style('white-space', 'nowrap') // required for ellipsis
+      .style('text-overflow', 'ellipsis')
+      .style('text-align', 'center')
+      .style('vertical-align', 'middle')
+      .style('visibility', function(datum) {
+        return (datum.dx < 15 || datum.dy < 15) ? 'hidden' : 'visible';
+      })
+      .text(function(datum) { return datum.n; });
+
+  // Complicated transition logic: See note in _handleInodes()
+  this._mapContainer.selectAll('div.leaf_rect_entering').transition()
+      .duration(thisTreeMap._enterDuration).delay(
+          this._firstTransition ? 0 : thisTreeMap._exitDuration +
+              thisTreeMap._updateDuration)
+      .attr('class', 'rect leaf_rect')
+      .style('opacity', '1')
+  this._mapContainer.selectAll('div.leaf_label_entering').transition()
+      .duration(thisTreeMap._enterDuration).delay(
+          this._firstTransition ? 0 : thisTreeMap._exitDuration +
+              thisTreeMap._updateDuration)
+      .attr('class', 'label leaf_label')
+      .style('opacity', '1')
+  this._mapContainer.selectAll('div.leaf_rect').transition()
+      .duration(thisTreeMap._updateDuration).delay(thisTreeMap._exitDuration)
+      .style('opacity', '1')
+      .style('left', function(datum){ return datum.x; })
+      .style('top', function(datum){ return datum.y; })
+      .style('width', function(datum){ return datum.dx; })
+      .style('height', function(datum){ return datum.dy; });
+  this._mapContainer.selectAll('div.leaf_label').transition()
+      .duration(thisTreeMap._updateDuration).delay(thisTreeMap._exitDuration)
+      .style('opacity', '1')
+      .style('visibility', function(datum) {
+          return (datum.dx < 15 || datum.dy < 15) ? 'hidden' : 'visible';
+      })
+      .style('left', function(datum){ return datum.x; })
+      .style('top', function(datum){ return datum.y; })
+      .style('width', function(datum) { return datum.dx; })
+      .style('height', function(datum) { return datum.dy; });
+  var exit = this._mapContainer.selectAll('div.leaf')
+      .data(leaves, function(datum) { return 'leaf-' + datum.id; })
+      .exit();
+  exit.selectAll('div.leaf_rect').transition()
+      .duration(thisTreeMap._exitDuration)
+      .style('opacity', 0);
+  exit.selectAll('div.leaf_label').transition()
+      .duration(thisTreeMap._exitDuration)
+      .style('opacity', 0);
+  exit.transition().delay(thisTreeMap._exitDuration + 1).remove();
+
+  console.log(leaves.length + ' leaves layed out.');
+  console.timeEnd('_handleLeaves');
+}
+
+D3SymbolTreeMap.prototype._makeSymbolBucketBackgroundImage = function(datum) {
+  if (!(datum.t === undefined && datum.depth == this._currentMaxDepth)) {
+    return 'none';
+  }
+  var text = '';
+  var lastStop = 0;
+  for (var x = 0; x < D3SymbolTreeMap._NM_SYMBOL_TYPES.length; x++) {
+    symbol_type = D3SymbolTreeMap._NM_SYMBOL_TYPES.charAt(x);
+    var stats = datum.symbol_stats[symbol_type];
+    if (stats !== undefined) {
+      if (text.length !== 0) {
+        text += ', ';
+      }
+      var percent = 100 * (stats.size / datum.value);
+      var nowStop = lastStop + percent;
+      var tempcolor = D3SymbolTreeMap.getColorForType(symbol_type);
+      var color = d3.rgb(tempcolor).toString();
+      text += color + ' ' + lastStop + '%, ' + color + ' ' +
+          nowStop + '%';
+      lastStop = nowStop;
+    }
+  }
+  return 'linear-gradient(' + (datum.dx > datum.dy ? 'to right' :
+                               'to bottom') + ', ' + text + ')';
+}
+
+D3SymbolTreeMap.prototype.pathFor = function(datum) {
+  if (datum.__path) return datum.__path;
+  parts=[];
+  node = datum;
+  while (node) {
+    if (node.k === 'p') { // path node
+      if(node.n !== '/') parts.unshift(node.n);
+    }
+    node = node.parent;
+  }
+  datum.__path = '/' + parts.join('/');
+  return datum.__path;
+}
+
+D3SymbolTreeMap.prototype._createHighlight = function(datum, selection) {
+  var x = parseInt(selection.style('left'));
+  var y = parseInt(selection.style('top'));
+  var w = parseInt(selection.style('width'));
+  var h = parseInt(selection.style('height'));
+  datum.highlight = this._mapContainer.append('div')
+      .attr('id', 'h-' + datum.id)
+      .attr('class', 'highlight')
+      .style('pointer-events', 'none')
+      .style('-webkit-user-select', 'none')
+      .style('z-index', '999999')
+      .style('position', 'absolute')
+      .style('top', y-2)
+      .style('left', x-2)
+      .style('width', w+4)
+      .style('height', h+4)
+      .style('margin', 0)
+      .style('padding', 0)
+      .style('border', '4px outset rgba(250,40,200,0.9)')
+      .style('box-sizing', 'border-box')
+      .style('opacity', 0.0);
+}
+
+D3SymbolTreeMap.prototype._showHighlight = function(datum, selection) {
+  if (datum === this._currentRoot) return;
+  if (datum.highlight === undefined) {
+    this._createHighlight(datum, selection);
+  }
+  datum.highlight.transition().duration(200).style('opacity', 1.0);
+}
+
+D3SymbolTreeMap.prototype._hideHighlight = function(datum, selection) {
+  if (datum.highlight === undefined) return;
+  datum.highlight.transition().duration(750)
+      .style('opacity', 0)
+      .each('end', function(){
+        if (datum.highlight) datum.highlight.remove();
+        delete datum.highlight;
+      });
+}
+
+D3SymbolTreeMap.prototype._createInfoBox = function() {
+  return d3.select('body')
+      .append('div')
+      .attr('id', 'infobox')
+      .style('z-index', '2147483647') // (2^31) - 1: Hopefully safe :)
+      .style('position', 'absolute')
+      .style('visibility', 'hidden')
+      .style('background-color', 'rgba(255,255,255, 0.9)')
+      .style('border', '1px solid black')
+      .style('padding', '10px')
+      .style('-webkit-user-select', 'none')
+      .style('box-shadow', '3px 3px rgba(70,70,70,0.5)')
+      .style('border-radius', '10px')
+      .style('white-space', 'nowrap');
+}
+
+D3SymbolTreeMap.prototype._showInfoBox = function(datum) {
+  this.infobox.text('');
+  var numSymbols = 0;
+  var sizeish = D3SymbolTreeMap._pretty(datum.value) + ' bytes (' +
+      D3SymbolTreeMap._byteify(datum.value) + ')';
+  if (datum.k === 'p' || datum.k === 'b') { // path or bucket
+    if (datum.symbol_stats) { // can be empty if filters are applied
+      for (var x = 0; x < D3SymbolTreeMap._NM_SYMBOL_TYPES.length; x++) {
+        symbol_type = D3SymbolTreeMap._NM_SYMBOL_TYPES.charAt(x);
+        var stats = datum.symbol_stats[symbol_type];
+        if (stats !== undefined) numSymbols += stats.count;
+      }
+    }
+  } else if (datum.k === 's') { // symbol
+    numSymbols = 1;
+  }
+
+  if (datum.k === 'p' && !datum.lastPathElement) {
+    this.infobox.append('div').text('Directory: ' + this.pathFor(datum))
+    this.infobox.append('div').text('Size: ' + sizeish);
+  } else {
+    if (datum.k === 'p') { // path
+      this.infobox.append('div').text('File: ' + this.pathFor(datum))
+      this.infobox.append('div').text('Size: ' + sizeish);
+    } else if (datum.k === 'b') { // bucket
+      this.infobox.append('div').text('Symbol Bucket: ' +
+          D3SymbolTreeMap._getSymbolDescription(datum.t));
+      this.infobox.append('div').text('Count: ' + numSymbols);
+      this.infobox.append('div').text('Size: ' + sizeish);
+      this.infobox.append('div').text('Location: ' + this.pathFor(datum))
+    } else if (datum.k === 's') { // symbol
+      this.infobox.append('div').text('Symbol: ' + datum.n);
+      this.infobox.append('div').text('Type: ' +
+          D3SymbolTreeMap._getSymbolDescription(datum.t));
+      this.infobox.append('div').text('Size: ' + sizeish);
+      this.infobox.append('div').text('Location: ' + this.pathFor(datum))
+    }
+  }
+  if (datum.k === 'p') {
+    this.infobox.append('div')
+        .text('Number of symbols: ' + D3SymbolTreeMap._pretty(numSymbols));
+    if (datum.symbol_stats) { // can be empty if filters are applied
+      var table = this.infobox.append('table')
+          .attr('border', 1).append('tbody');
+      var header = table.append('tr');
+      header.append('th').text('Type');
+      header.append('th').text('Count');
+      header.append('th')
+          .style('white-space', 'nowrap')
+          .text('Total Size (Bytes)');
+      for (var x = 0; x < D3SymbolTreeMap._NM_SYMBOL_TYPES.length; x++) {
+        symbol_type = D3SymbolTreeMap._NM_SYMBOL_TYPES.charAt(x);
+        var stats = datum.symbol_stats[symbol_type];
+        if (stats !== undefined) {
+          var tr = table.append('tr');
+          tr.append('td')
+              .style('white-space', 'nowrap')
+              .text(D3SymbolTreeMap._getSymbolDescription(
+                  symbol_type));
+          tr.append('td').text(D3SymbolTreeMap._pretty(stats.count));
+          tr.append('td').text(D3SymbolTreeMap._pretty(stats.size));
+        }
+      }
+    }
+  }
+  this.infobox.style('visibility', 'visible');
+}
+
+D3SymbolTreeMap.prototype._hideInfoBox = function(datum) {
+  this.infobox.style('visibility', 'hidden');
+}
+
+D3SymbolTreeMap.prototype._moveInfoBox = function(event) {
+  var element = document.getElementById('infobox');
+  var w = element.offsetWidth;
+  var h = element.offsetHeight;
+  var offsetLeft = 10;
+  var offsetTop = 10;
+
+  var rightLimit = window.innerWidth;
+  var rightEdge = event.pageX + offsetLeft + w;
+  if (rightEdge > rightLimit) {
+    // Too close to screen edge, reflect around the cursor
+    offsetLeft = -1 * (w + offsetLeft);
+  }
+
+  var bottomLimit = window.innerHeight;
+  var bottomEdge = event.pageY + offsetTop + h;
+  if (bottomEdge > bottomLimit) {
+    // Too close ot screen edge, reflect around the cursor
+    offsetTop = -1 * (h + offsetTop);
+  }
+
+  this.infobox.style('top', (event.pageY + offsetTop) + 'px')
+      .style('left', (event.pageX + offsetLeft) + 'px');
+}
+
+D3SymbolTreeMap.prototype.biggestSymbols = function(maxRecords) {
+  var result = undefined;
+  var smallest = undefined;
+  var sortFunction = function(a,b) {
+    var result = b.value - a.value;
+    if (result !== 0) return result; // sort by size
+    var pathA = treemap.pathFor(a); // sort by path
+    var pathB = treemap.pathFor(b);
+    if (pathA > pathB) return 1;
+    if (pathB > pathA) return -1;
+    return a.n - b.n; // sort by symbol name
+  };
+  this.visitFromDisplayedRoot(function(datum) {
+    if (datum.children) return; // ignore non-leaves
+    if (!result) { // first element
+      result = [datum];
+      smallest = datum.value;
+      return;
+    }
+    if (result.length < maxRecords) { // filling the array
+      result.push(datum);
+      return;
+    }
+    if (datum.value > smallest) { // array is already full
+      result.push(datum);
+      result.sort(sortFunction);
+      result.pop(); // get rid of smallest element
+      smallest = result[maxRecords - 1].value; // new threshold for entry
+    }
+  });
+  result.sort(sortFunction);
+  return result;
+}
+
+D3SymbolTreeMap.prototype.biggestPaths = function(maxRecords) {
+  var result = undefined;
+  var smallest = undefined;
+  var sortFunction = function(a,b) {
+    var result = b.value - a.value;
+    if (result !== 0) return result; // sort by size
+    var pathA = treemap.pathFor(a); // sort by path
+    var pathB = treemap.pathFor(b);
+    if (pathA > pathB) return 1;
+    if (pathB > pathA) return -1;
+    console.log('warning, multiple entries for the same path: ' + pathA);
+    return 0; // should be impossible
+  };
+  this.visitFromDisplayedRoot(function(datum) {
+    if (!datum.lastPathElement) return; // ignore non-files
+    if (!result) { // first element
+      result = [datum];
+      smallest = datum.value;
+      return;
+    }
+    if (result.length < maxRecords) { // filling the array
+      result.push(datum);
+      return;
+    }
+    if (datum.value > smallest) { // array is already full
+      result.push(datum);
+      result.sort(sortFunction);
+      result.pop(); // get rid of smallest element
+      smallest = result[maxRecords - 1].value; // new threshold for entry
+    }
+  });
+  result.sort(sortFunction);
+  return result;
+}
diff --git a/runtime/third_party/binary_size/src/template/index.html b/runtime/third_party/binary_size/src/template/index.html
new file mode 100644
index 0000000..7e1a1fc
--- /dev/null
+++ b/runtime/third_party/binary_size/src/template/index.html
@@ -0,0 +1,525 @@
+<!--
+  Copyright 2014 The Chromium Authors. All rights reserved.
+  Use of this source code is governed by a BSD-style license that can be
+  found in the LICENSE file.
+-->
+<html>
+<head>
+<title>Binary Size Analysis</title>
+<script src="d3/d3.js" charset="utf-8"></script>
+<script src="D3SymbolTreeMap.js" charset="utf-8"></script>
+<script src="data.js" charset="utf-8"></script>
+<style>
+body {
+    margin: 0px;
+    padding: 5px;
+}
+.swatch {
+    border: 1px solid rgb(100,100,100);
+    -webkit-user-select: none;
+    cursor: default;
+}
+</style>
+<script>
+var treemap;
+var filterChanging = false;
+var savedSettings = {};
+
+function init() {
+    if (window.metadata !== undefined && window.metadata.subtitle) {
+        document.getElementById('subtitle').innerHTML = ': ' + escape(metadata.subtitle);
+    }
+    initFilterOptions();
+    treemap = new D3SymbolTreeMap(
+        savedSettings.width,
+        savedSettings.height,
+        savedSettings.maxLevels);
+    treemap.init();
+}
+
+function getIdealSizes() {
+    var width = window.innerWidth - 20;
+    var height = window.innerHeight - 70;
+    return {'width': width, 'height': height};
+}
+
+function showReport(title, data, headers, dataFunction, styleFunction) {
+    var div =  d3.select('body').append('div')
+        .style('margin', '0')
+        .style('padding', '5px')
+        .style('position', 'absolute')
+        .style('top', '10%')
+        .style('left', '10%')
+        .style('background-color', 'rgba(255,255,255,0.9)')
+        .style('width', '80%')
+        .style('height', '80%')
+        .style('z-index', '2147483647')
+        .style('border', '3px ridge grey')
+        .style('box-shadow', '10px 10px 5px rgba(80,80,80,0.7)')
+        .style('text-align', 'center')
+        .style('border-radius', '10px');
+    var titlebar = div.append('div')
+        .style('margin', '0')
+        .style('padding', '5px')
+        .style('position', 'absolute')
+        .style('top', '0%')
+        .style('left', '0%')
+        .style('width', '100%')
+        .style('height', '10%')
+        .style('font-size', 'x-large');
+    titlebar.text(title);
+    var controls = div.append('div')
+        .style('margin', '0')
+        .style('padding', '5px')
+        .style('position', 'absolute')
+        .style('top', '90%')
+        .style('left', '0%')
+        .style('width', '100%')
+        .style('height', '10%');
+    controls.append('input').attr('type', 'button')
+        .attr('value', 'Dismiss')
+        .on('click', function(){div.remove();});
+
+    var tableDiv = div.append('div')
+        .style('overflow', 'auto')
+        .style('position', 'absolute')
+        .style('top', '10%')
+        .style('left', '0%')
+        .style('width', '100%')
+        .style('height', '80%')
+        .style('border-top', '1px solid rgb(230,230,230)')
+        .style('border-bottom', '1px solid rgb(230,230,230)');
+    var table = tableDiv.append('table')
+        .attr('border', '1')
+        .attr('cellspacing', '0')
+        .attr('cellpadding', '2')
+        .style('margin-left', 'auto')
+        .style('margin-right', 'auto');
+    var header = table.append('tr');
+    for (var i = 0; i < headers.length; i++) {
+        header.append('th').text(headers[i]);
+    }
+
+    for (var i = 0; i < data.length; i++) {
+        var row = table.append('tr');
+        for (j = 0; j < headers.length; j++) {
+            var td = row.append('td');
+            if (styleFunction) {
+                styleFunction.call(this, td, j);
+            }
+            dataFunction.call(this, data[i], j, td);
+        }
+    }
+}
+
+function bigSymbolsReport() {
+    var list = treemap.biggestSymbols(100);
+    var headers = ['Rank', 'Size (Bytes)', 'Type', 'Location'];
+    var styleFunction = function(selection, index) {
+        if (index === 3) {
+            selection.style('font-family', 'monospace');
+        }
+    };
+    var recordIndex = 1;
+    var dataFunction = function(record, index, cell) {
+        if (index === 0) {
+            cell.text(recordIndex++);
+        } else if (index === 1) {
+            cell.text(D3SymbolTreeMap._pretty(record.value));
+        } else if (index === 2) {
+            cell.text(record.t);
+        } else {
+            if (treemap.pathFor(record).indexOf('/out') == 0) {
+                cell.append('span').text(treemap.pathFor(record));
+                cell.append('br');
+                cell.append('span').text('Symbol: ');
+                cell.append('span').text(record.n);
+            } else {
+                var href = 'https://code.google.com/p/chromium/codesearch#chromium/src'
+                    + treemap.pathFor(record)
+                    + '&q='
+                    + record.n;
+                cell.append('a')
+                    .attr('href', href)
+                    .attr('target', '_blank')
+                    .text(treemap.pathFor(record));
+                cell.append('br');
+                cell.append('span').text('Symbol: ');
+                cell.append('span').text(record.n);
+            }
+        }
+    };
+    showReport('100 Largest Symbols', list, headers, dataFunction, styleFunction);
+}
+
+function bigPathsReport() {
+    var list = treemap.biggestPaths(100);
+    var headers = ['Rank', 'Size (Bytes)', 'Location'];
+    var styleFunction = function(selection, index) {
+        if (index === 2) {
+            selection.style('font-family', 'monospace');
+        }
+    };
+    var recordIndex = 1;
+    var dataFunction = function(record, index, cell) {
+        if (index === 0) {
+            cell.text(recordIndex++);
+        } else if (index === 1) {
+            cell.text(D3SymbolTreeMap._pretty(record.value));
+        } else if (index === 2) {
+            if (treemap.pathFor(record).indexOf('/out') == 0) {
+                cell.text(treemap.pathFor(record));
+            } else {
+                var href = 'https://code.google.com/p/chromium/codesearch#chromium/src' + treemap.pathFor(record);
+                cell.append('a')
+                    .attr('href', href)
+                    .attr('target', '_blank')
+                    .text(treemap.pathFor(record));
+            }
+
+        }
+    };
+    showReport('100 Largest Paths', list, headers, dataFunction, styleFunction);
+}
+
+function symbolFilterTextChanged() {
+    if (filterChanging) return true;
+    filterChanging = true;
+    var enabled = document.getElementById('symbol_types_filter').value;
+    for (var x=0; x<=25; x++) {
+        var checkBox = document.getElementById('check_' + x);
+        checkBox.checked = (enabled.indexOf(checkBox.value) != -1);
+    }
+    filterChanging = false;
+}
+
+function updateFilterText() {
+    if (filterChanging) return true;
+    filterChanging = true;
+    var text = '';
+    for (var x=0; x<=25; x++) {
+        var checkBox = document.getElementById('check_' + x);
+        if (checkBox.checked) {
+            text += checkBox.value;
+        }
+    }
+    document.getElementById('symbol_types_filter').value=text;
+    filterChanging = false;
+}
+
+function initFilterOptions() {
+    updateFilterText();
+    for (var x=0; x<=25; x++) {
+        var checkBox = document.getElementById('check_' + x);
+        checkBox.onchange=updateFilterText;
+        var swatch = document.getElementById('swatch_' + x);
+        swatch.style.backgroundColor = D3SymbolTreeMap.getColorForType(checkBox.value).toString();
+    }
+    var gteCheckbox = document.getElementById('check_gte');
+    gteCheckbox.onchange = function() {
+        document.getElementById('symbol_filter_gte').disabled = !gteCheckbox.checked;
+    }
+    var regexCheckbox = document.getElementById('check_regex');
+    regexCheckbox.onchange = function() {
+        document.getElementById('symbol_filter_regex').disabled = !regexCheckbox.checked;
+    }
+    var excludeRegexCheckbox = document.getElementById('check_exclude_regex');
+    excludeRegexCheckbox.onchange = function() {
+        document.getElementById('symbol_filter_exclude_regex').disabled = !excludeRegexCheckbox.checked;
+    }
+    var idealSizes = getIdealSizes();
+    document.getElementById('width').value = idealSizes.width;
+    document.getElementById('height').value = idealSizes.height;
+    saveFilterSettings();
+}
+
+function filterSetAll(enabled) {
+    for (var x=0; x<=25; x++) {
+        var checkBox = document.getElementById('check_' + x);
+        checkBox.checked = enabled;
+    }
+    updateFilterText();
+}
+
+function showOptions() {
+    loadFilterSettings();
+    var container = document.getElementById('options_container');
+    var w = container.offsetWidth;
+    var h = container.offsetHeight;
+    container.style.margin = '-' + (h/2) + 'px 0 0 -' + (w/2) + 'px';
+    container.style.visibility = 'visible';
+}
+
+function hideOptions() {
+    var container = document.getElementById('options_container');
+    container.style.visibility = 'hidden';
+}
+
+function applySettings() {
+    hideOptions();
+    var oldWidth = savedSettings.width;
+    var oldHeight = savedSettings.height;
+    var oldSymbols = savedSettings.symbolTypes;
+    var oldRegex = savedSettings.regex;
+    var oldExcludeRegex = savedSettings.excludeRegex;
+    var oldGte = savedSettings.gte;
+    var oldMaxLevels = savedSettings.maxLevels;
+    saveFilterSettings();
+    var resizeNeeded = oldWidth !== savedSettings.width || oldHeight !== savedSettings.height;
+    var regexChanged = oldRegex !== savedSettings.regex;
+    var excludeRegexChanged = oldExcludeRegex !== savedSettings.excludeRegex;
+    var symbolsChanged = oldSymbols !== savedSettings.symbolTypes;
+    var gteChanged = oldGte !== savedSettings.gte;
+    var filterChanged = regexChanged || excludeRegexChanged || symbolsChanged || gteChanged;
+    var maxLevelsChanged = oldMaxLevels !== savedSettings.maxLevels;
+
+    if (filterChanged) {
+        // Type filters
+        typeFilter = function(datum) {
+            if (datum.depth === 0) return true; // root node
+            if (datum.t === undefined) return true;
+            return savedSettings.symbolTypes !== undefined &&
+                savedSettings.symbolTypes.indexOf(datum.t) !== -1;
+        }
+
+        // Regex filter
+        var regexFilter = undefined;
+        if (savedSettings.regex !== undefined && savedSettings.regex.length > 0) {
+            console.log('filter: regex is "' + savedSettings.regex + '"');
+            var regex = new RegExp(savedSettings.regex);
+            regexFilter = function(datum) {
+                if (datum.depth === 0) return true; // root node
+                var fullName = this.pathFor(datum);
+                if (datum.children === undefined) { // it is a leaf node (symbol)
+                    fullName += ':' + datum.n;
+                }
+                return regex.test(fullName);
+            }
+        }
+
+        // Exclude regex filter
+        var excludeRegexFilter = undefined;
+        if (savedSettings.excludeRegex !== undefined && savedSettings.excludeRegex.length > 0) {
+            console.log('filter: exclude-regex is "' + savedSettings.excludeRegex + '"');
+            var excludeRegex = new RegExp(savedSettings.excludeRegex);
+            excludeRegexFilter = function(datum) {
+                if (datum.depth === 0) return true; // root node
+                var fullName = this.pathFor(datum);
+                if (datum.children === undefined) { // it is a leaf node (symbol)
+                    fullName += ':' + datum.n;
+                }
+                return !excludeRegex.test(fullName);
+            }
+        }
+
+        // Size filter
+        var sizeFilter = undefined;
+        if (savedSettings.gte !== undefined) {
+            console.log('filter: minimum size is ' + savedSettings.gte + ' bytes');
+            sizeFilter = function(datum) {
+                if (datum.children !== undefined) return true; // non-leaf
+                if (datum.value === undefined) console.log('whoops');
+                return datum.value >= savedSettings.gte;
+            }
+        }
+
+        // Make a filter to apply to the tree
+        var filter = function(datum) {
+            if (typeFilter && !typeFilter.call(this, datum)) return false;
+            if (regexFilter && !regexFilter.call(this, datum)) return false;
+            if (excludeRegexFilter && !excludeRegexFilter.call(this, datum)) return false;
+            if (sizeFilter && !sizeFilter.call(this, datum)) return false;
+            return true;
+        };
+        treemap.filter(filter);
+    }
+
+    // Adjust levels if needed.
+    if (maxLevelsChanged) {
+        treemap.setMaxLevels(savedSettings.maxLevels);
+    }
+
+    // Resize map if necessary.
+    if (resizeNeeded) {
+        console.log('desired treemap dimensions have changed, requesting resize');
+        treemap.resize(savedSettings.width, savedSettings.height);
+    }
+}
+
+function cancelSettings() {
+    hideOptions();
+    loadFilterSettings();
+}
+
+function saveFilterSettings() {
+    savedSettings.symbolTypes = document.getElementById('symbol_types_filter').value;
+    if (document.getElementById('check_regex').checked) {
+        savedSettings.regex = document.getElementById('symbol_filter_regex').value;
+    } else {
+        savedSettings.regex = undefined;
+    }
+    if (document.getElementById('check_exclude_regex').checked) {
+        savedSettings.excludeRegex = document.getElementById('symbol_filter_exclude_regex').value;
+    } else {
+        savedSettings.excludeRegex = undefined;
+    }
+    if (document.getElementById('check_gte').checked) {
+        savedSettings.gte = parseInt(document.getElementById('symbol_filter_gte').value);
+    } else {
+        savedSettings.gte = undefined;
+    }
+    savedSettings.width = parseInt(document.getElementById('width').value);
+    savedSettings.height = parseInt(document.getElementById('height').value);
+    savedSettings.maxLevels = parseInt(document.getElementById('max_levels').value);
+}
+
+function loadFilterSettings() {
+    document.getElementById('symbol_types_filter').value = savedSettings.symbolTypes;
+    symbolFilterTextChanged();
+    if (savedSettings.regex !== undefined) {
+        document.getElementById('check_regex').checked = true;
+        document.getElementById('symbol_filter_regex').value = savedSettings.regex;
+    } else {
+        document.getElementById('check_regex').checked = false;
+    }
+    if (savedSettings.excludeRegex !== undefined) {
+        document.getElementById('check_exclude_regex').checked = true;
+        document.getElementById('symbol_filter_exclude_regex').value = savedSettings.excludeRegex;
+    } else {
+        document.getElementById('check_exclude_regex').checked = false;
+    }
+    if (savedSettings.gte !== undefined) {
+        document.getElementById('check_gte').checked = true;
+        document.getElementById('symbol_filter_gte').value = savedSettings.gte;
+    } else {
+        document.getElementById('check_gte').checked = false;
+    }
+    document.getElementById('width').value = savedSettings.width;
+    document.getElementById('height').value = savedSettings.height;
+    document.getElementById('max_levels').value = savedSettings.maxLevels;
+}
+
+function escape(str) {
+    return str.replace(/&/g, '&amp;')
+              .replace(/"/g, '&quot;')
+              .replace(/</g, '&lt;')
+              .replace(/>/g, '&gt;');
+}
+</script>
+</head>
+<body onload='init()'>
+<div style='position: absolute; top: 5px; left: 5px;'>
+  <input type='button' onclick='showOptions()' value='Options &amp; Legend...'>
+  <span style='-webkit-user-select: none; cursor: help;' title='Click to view the symbol legend or to configure filters and options for the treemap'>[?]</span>
+</div>
+<div style='position: absolute; right: 5px; top: 5px; white-space: nowrap;'>
+    Reports:
+    <input type='button' onclick='bigSymbolsReport()' value='Large Symbols' title='Click to view a report of the largest 100 symbols that are with the bounds of the treemap that is currently displayed.'>
+    <input type='button' onclick='bigPathsReport()' value='Large Files' title='Click to view a report of the largest 100 source files that are with the bounds of the treemap that is currently displayed.'>
+</div>
+<div style='text-align: center; margin-bottom: 5px;'>
+    <span style='font-size: x-large; font-weight: bold; font-variant: small-caps'>Binary Size Analysis<span id='subtitle'></span></span>
+    <br><span style='font-size: small; font-style: italic;'>Double-click a box to zoom in, double-click outermost title to zoom out.</span>
+</div>
+<table id='options_container' style='visibility: hidden; border: 3px ridge grey; padding: 0px; top: 50%; left: 50%; position: fixed; z-index: 2147483646; overflow: auto; background-color: rgba(255,255,255,0.9); border-radius: 10px; box-shadow: 10px 10px 5px rgba(80,80,80,0.7);'><tr><td style='vertical-align: top'>
+    <table cellspacing=0 cellborder=0 style='width:100%'>
+        <tr><th colspan=3 style='padding-bottom: .25em; text-decoration: underline;'>Symbol Types To Show</th></tr>
+        <tr>
+            <td style='width: 33%; white-space: nowrap; vertical-align: top;'>
+                    <span class='swatch' id='swatch_0'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_0' value='A'>Global absolute (A)
+                <br><span class='swatch' id='swatch_1'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_1' value='B'>Global uninitialized data (B)
+                <br><span class='swatch' id='swatch_2'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_2' value='b'>Local uninitialized data (b)
+                <br><span class='swatch' id='swatch_3'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_3' value='C'>Global uninitialized common (C)
+                <br><span class='swatch' id='swatch_4'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_4' value='D'>Global initialized data (D)
+                <br><span class='swatch' id='swatch_5'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_5' value='d'>Local initialized data (d)
+                <br><span class='swatch' id='swatch_6'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_6' value='G'>Global small initialized data (G)
+                <br><span class='swatch' id='swatch_7'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_7' value='g'>Local small initialized data (g)
+                <br><span class='swatch' id='swatch_8'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_8' value='i'>Indirect function (i)
+            </td>
+            <td style='width: 33%; white-space: nowrap; vertical-align: top;'>
+                    <span class='swatch' id='swatch_9'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_9' value='N'>Debugging (N)
+                <br><span class='swatch' id='swatch_10'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_10' value='p'>Stack unwind (p)
+                <br><span class='swatch' id='swatch_11'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_11' value='R'>Global read-only data (R)
+                <br><span class='swatch' id='swatch_12'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_12' value='r'>Local read-only data (r)
+                <br><span class='swatch' id='swatch_13'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_13' value='S'>Global small uninitialized data (S)
+                <br><span class='swatch' id='swatch_14'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_14' value='s'>Local small uninitialized data (s)
+                <br><span class='swatch' id='swatch_15'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_15' value='T'>Global code (T)
+                <br><span class='swatch' id='swatch_16'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_16' value='t'>Local code (t)
+                <br><span class='swatch' id='swatch_17'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_17' value='U'>Undefined (U)
+            </td>
+            <td style='width: 33%; white-space: nowrap; vertical-align: top;'>
+                    <span class='swatch' id='swatch_18'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_18' value='u'>Unique (u)
+                <br><span class='swatch' id='swatch_19'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_19' value='V'>Global weak object (V)
+                <br><span class='swatch' id='swatch_20'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_20' value='v'>Local weak object (v)
+                <br><span class='swatch' id='swatch_21'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_21' value='W'>Global weak symbol (W)
+                <br><span class='swatch' id='swatch_22'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_22' value='w'>Local weak symbol (w)
+                <br><span class='swatch' id='swatch_23'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_23' value='@'>Vtable entry (@)
+                <br><span class='swatch' id='swatch_24'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_24' value='-'>STABS debugging (-)
+                <br><span class='swatch' id='swatch_25'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_25' value='?'>Unrecognized (?)
+            </td>
+        </tr>
+        <tr><td colspan=3 style='text-align: center; white-space: nowrap; padding-top: 1em;'>
+            Select <input type='button' onclick='filterSetAll(true)' value='All'>,
+            <input type='button' onclick='filterSetAll(false)' value='None'>,
+            or type a string: <input id='symbol_types_filter' size=30 value='' onkeyup='symbolFilterTextChanged()' onblur='updateFilterText()'>
+            <span style='-webkit-user-select: none; cursor: help;' title='Enter codes from the list above for the symbols you want to see. The checkboxes will update automatically to match the string that you enter.'>[?]</span>
+        </td></tr>
+   </table>
+</td></tr><tr><td style='vertical-align: top; padding-top: 10px; border-top: 1px solid grey;'>
+    <table cellspacing=0 cellborder=0 style='width: 100%'>
+        <tr><th colspan=2 style='padding-bottom: .25em; text-decoration: underline;'>Advanced Options</th></tr>
+        <tr>
+            <td style='white-space: nowrap; vertical-align: top;'>
+                <input type='checkbox' id='check_regex'>
+                Only include symbols matching this regex:
+            </td>
+            <td style='text-align: right; vertical-align: top;'>
+                <input disabled id='symbol_filter_regex' size=30 value='' style='text-align: right;'>
+                <span style='-webkit-user-select: none; cursor: help;' title='Enter a javascript regex. Only symbols that match this regex will be shown. This filter applies before any exclusion regex specified below. The format of each symbol is [path]:[symbol_name]'>[?]</span>
+            </td>
+        </tr>
+        <tr>
+            <td style='white-space: nowrap; vertical-align: top;'>
+                <input type='checkbox' id='check_exclude_regex'>
+                Exclude all symbols matching this regex:
+            </td>
+            <td style='text-align: right; vertical-align: top;'>
+                <input disabled id='symbol_filter_exclude_regex' size=30 value='' style='text-align: right;'>
+                <span style='-webkit-user-select: none; cursor: help;' title='Enter a javascript regex. Symbols that match this tegex will not be shown. This filter applies after any inclusion filter specified above. The format of each symbol is [path]:[symbol_name]'>[?]</span>
+            </td>
+        </tr>
+        <tr>
+            <td style='white-space: nowrap; vertical-align: top;'>
+                <input type='checkbox' id='check_gte'>
+                Only include symbols that are at least <span style='font-style: italic;'>n</span> bytes:
+            </td>
+            <td style='text-align: right; vertical-align: top;'>
+                <input disabled id='symbol_filter_gte' size=8 value='' style='text-align: right;'>
+                <span style='-webkit-user-select: none; cursor: help;' title='Symbols whose size is less than this value will be hidden.'>[?]</span>
+            </td>
+        </tr>
+        <tr>
+            <td style='white-space: nowrap vertical-align: top;;'>
+                Show at most <span style='font-style: italic;'>n</span> levels of detail at a time:
+            </td>
+            <td style='text-align: right; vertical-align: top;'>
+                <input id='max_levels' size=4 value='2' style='text-align: right;'><span style='-webkit-user-select: none; cursor: help;' title='Increasing this value shows more detail without the need to zoom, but uses more computing power.'>[?]</span>
+            </td>
+        </tr>
+        <tr>
+            <td style='white-space: nowrap vertical-align: top;;'>
+                Set the size of the treemap to <span style='font-style: italic;'>W x H</span> pixels:
+            </td>
+            <td style='text-align: right; vertical-align: top;'>
+                <input id='width' size=4 value='' style='text-align: right;'>
+                &nbsp;x&nbsp;<input id='height' size=4 value='' style='text-align: right;'>
+            </td>
+        </tr>
+    </table>
+</td></tr>
+<tr><td style='padding-top: 10px; text-align: right; border-top: 1px solid grey'>
+    <input type='button' value='Apply' onclick='applySettings()'>
+    <input type='button' value='Cancel' onclick='cancelSettings()'>
+</td></tr></table>
+</body>
+</html>
diff --git a/runtime/third_party/binary_size/src/template/test-data-generator.html b/runtime/third_party/binary_size/src/template/test-data-generator.html
new file mode 100644
index 0000000..9c6790a
--- /dev/null
+++ b/runtime/third_party/binary_size/src/template/test-data-generator.html
@@ -0,0 +1,157 @@
+<!DOCTYPE html>
+<!--
+  Copyright 2014 The Chromium Authors. All rights reserved.
+  Use of this source code is governed by a BSD-style license that can be
+  found in the LICENSE file.
+-->
+<html>
+<head>
+<script>
+function rnd(max) {
+    return Math.round(Math.random()*max);
+}
+
+function gen() {
+  var dirs1=['usr1', 'etc1', 'var1'];
+  var dirs2=['aaa2', 'bbb2', 'ccc2', 'ddd2', 'eee2', 'fff2', 'ggg2', 'hhh2',
+             'frobozz2', 'kazaam2', 'shazam2'];
+  var dirs3=['iii3', 'jjj3', 'kkk3', 'lll3', 'mmm3', 'nnn3', 'ooo3', 'ppp3',
+             'wonderllama3', 'excelsior3', 'src3'];
+  var filenames=['awesome.cc', 'rad.h', 'tubular.cxx', 'cool.cc', 'groovy.h',
+                 'excellent.c', 'gnarly.h', 'green.C', 'articulate.cc'];
+  //All possible types (we only see a subset in practice): 'ABbCDdGgiNpRrSsTtUuVvWw-?';
+  var nm_symbol_types = 'trd';
+  var minSize = 4;
+  var maxSize = 10000;
+  var numGen = 300000;
+  var text = 'var nm_data=[\n';
+  var vtablePercent = 5;
+  for (var x=0; x<numGen; x++) {
+    var path = '/' +
+        dirs1[rnd(dirs1.length - 1)] + '/' +
+        dirs2[rnd(dirs2.length - 1)] + '/' +
+        dirs3[rnd(dirs3.length - 1)] + '/' +
+        filenames[rnd(filenames.length - 1)];
+    var isVtable = Math.floor((Math.random()*100)+1) <= vtablePercent;
+    var size = rnd(maxSize);
+    var symbol_name;
+    var type;
+    if (!isVtable) {
+      symbol_name = 'sym' + x.toString(16);
+      type = nm_symbol_types.charAt(rnd(nm_symbol_types.length - 1));
+    } else {
+      symbol_name = 'vtable for ' + x.toString(16);
+      type = '@'
+    }
+    text = text + "{'n': '" + symbol_name +
+        "', 't': '" + type +
+        "', 's': " + size +
+        ", 'p': '" + path + "'},\n";
+  }
+  text += '];';
+
+  eval(text);
+  var treeified = to_d3_tree(nm_data);
+  generateDownloadLink('tree_data=' + JSON.stringify(treeified));
+}
+
+function generateDownloadLink(content) {
+  var blob = new Blob([content], {type: 'text/plain'});
+  var link = document.createElement('a');
+  link.download = 'generated-content.txt';
+  link.href = window.URL.createObjectURL(blob);
+  link.textContent = 'Download ready, click here.';
+  link.dataset.downloadurl = ['text/plain', link.download, link.href].join(':');
+  link.onclick = function(e) {
+    if ('disabled' in this.dataset) { return false; }
+    link.dataset.disabled = true;
+    setTimeout(function() { window.URL.revokeObjectURL(link.href); }, 1500);
+  };
+  document.getElementById('linkcontainer').innerHTML = '';
+  document.getElementById('linkcontainer').appendChild(link);
+}
+
+/**
+ * This function takes in an array of nm records and converts them into a
+ * hierarchical data structure suitable for use in a d3-base treemap layout.
+ * Leaves are individual symbols. The parents of the leaves are logical
+ * groupings by common symbol-type (for BSS, read-only data, code, etc).
+ * Above this, each node represents part of a filesystem path relative
+ * to the parent node. The root node has the name '/', and represents
+ * a root (though not necessarily THE root) of a file system traversal.
+ * The root node also has a special property, 'maxDepth', to which is bound
+ * the deepest level of nesting that was found during conversion: for the
+ * record at path /a/b/c/d.foo, the maxDepth will be 6; the file 'd.foo'
+ * is at depth 4, the type-bucket is depth 5 and the symbols are depth 6.
+ */
+function to_d3_tree(records) {
+  var result = {'n': '/', 'children': [], 'k': 'p'};
+  var maxDepth = 0;
+  //{'n': 'symbol1', 't': 'b', 's': 1000, 'p': '/usr/local/foo/foo.cc'},
+  for (index in records) {
+    var record = records[index];
+    var parts = record.p.split("/");
+    var node = result;
+    var depth = 0;
+    // Walk the tree and find the file that is named by the "location"
+    // field of the record. We create any intermediate nodes required.
+    // This is directly analogous to "mkdir -p".
+    while(parts.length > 0) {
+      var part = parts.shift();
+      if (part.length == 0) continue;
+      depth++;
+      node = _mk_child(node, part, record.s);
+      node.k = 'p'; // p for path
+    }
+    node.lastPathElement = true;
+
+    // 'node' is now the file node. Find the symbol-type bucket.
+    node = _mk_child(node, record.t, record.s);
+    node.t = record.t;
+    node.k = 'b'; // b for bucket
+    depth++;
+    // 'node' is now the symbol-type bucket. Make the child entry.
+    node = _mk_child(node, record.n, record.s);
+    delete node.children;
+    node.value = record.s;
+    node.t = record.t;
+    node.k = 's'; // s for symbol
+    depth++;
+
+    maxDepth = Math.max(maxDepth, depth);
+  }
+  result.maxDepth = maxDepth;
+  return result;
+}
+
+/**
+ * Given a node and a name, return the child within node.children whose
+ * name matches the specified name. If necessary, a new child node is
+ * created and appended to node.children.
+ * If this method creates a new node, the 'name' attribute is set to the
+ * specified name and the 'children' attribute is an empty array, and
+ * total_size is the specified size. Otherwise, the existing node is
+ * returned and its total_size value is incremented by the specified size.
+ */
+function _mk_child(node, name, size) {
+  var child = undefined;
+  for (child_index in node.children) {
+    if (node.children[child_index].n == name) {
+      child = node.children[child_index];
+    }
+  }
+  if (child === undefined) {
+    child = {'n': name, 'children': []};
+    node.children.push(child);
+  }
+  return child;
+}
+</script>
+</head>
+<body style='white-space: pre; font-family: monospace;'>
+This script generates sample data for use in D3SymbolTreeMap, and can be used
+for testing.
+<input type=button onclick='gen();' value='Generate data'></input>
+<div id='linkcontainer'></div>
+</body>
+</html>
diff --git a/runtime/third_party/d3/README.chromium b/runtime/third_party/d3/README.chromium
new file mode 100644
index 0000000..7697762
--- /dev/null
+++ b/runtime/third_party/d3/README.chromium
@@ -0,0 +1,31 @@
+Name: d3
+Short Name: d3
+URL: https://github.com/mbostock/d3
+Version: 3.4.4
+Date: Mon Mar 24 20:45:44 2014 -0700
+Revision: fa55eead411a3c1b01703cb1ddfd59ccc0b23124
+License: BSD 3-Clause
+License File: src/LICENSE
+Security Critical: No
+License Android Compatible: Yes
+
+Description:
+A JavaScript library for manipulating documents based on data.
+
+Subject to the security patch(es) described below, you MAY include d3 in web-facing content, such
+as in pages generated by bots or tools.
+
+
+Local Modifications:
+1. Deleted everything except for:
+* d3.js         the standalone non-minified library
+* LICENSE       the BSD-style 3-Clause license
+* README.md     the readme file from github, for basic information
+
+2. Applied the following patches at the request of security:
+patches/001_no_html.patch        Disables the html() convenience functions, which could be used to
+                                 inject arbitrary content into the page. Instead of using html(),
+                                 programmatically create the individual nodes and/or text that you
+                                 require.
+                                 The html() methods have been modified to throw exceptions that
+                                 make it obvious that this feature is disabled for security.
diff --git a/runtime/third_party/d3/README.dart b/runtime/third_party/d3/README.dart
new file mode 100644
index 0000000..6abfe09
--- /dev/null
+++ b/runtime/third_party/d3/README.dart
@@ -0,0 +1 @@
+A local copy of third_party/d3 from Chromium project.
\ No newline at end of file
diff --git a/runtime/third_party/d3/patches/001_no_html.patch b/runtime/third_party/d3/patches/001_no_html.patch
new file mode 100644
index 0000000..3c976b0
--- /dev/null
+++ b/runtime/third_party/d3/patches/001_no_html.patch
@@ -0,0 +1,24 @@
+diff --git a/third_party/d3/src/d3.js b/third_party/d3/src/d3.js
+index a3e4b95..8a98c4d 100644
+--- a/third_party/d3/src/d3.js
++++ b/third_party/d3/src/d3.js
+@@ -713,6 +713,7 @@
+     }) : this.node().textContent;
+   };
+   d3_selectionPrototype.html = function(value) {
++    throw "disallowed by chromium security";
+     return arguments.length ? this.each(typeof value === "function" ? function() {
+       var v = value.apply(this, arguments);
+       this.innerHTML = v == null ? "" : v;
+@@ -9274,9 +9275,11 @@
+     return JSON.parse(request.responseText);
+   }
+   d3.html = function(url, callback) {
++    throw "disallowed by chromium security";
+     return d3_xhr(url, "text/html", d3_html, callback);
+   };
+   function d3_html(request) {
++    throw "disallowed by chromium security";
+     var range = d3_document.createRange();
+     range.selectNode(d3_document.body);
+     return range.createContextualFragment(request.responseText);
diff --git a/runtime/third_party/d3/src/LICENSE b/runtime/third_party/d3/src/LICENSE
new file mode 100644
index 0000000..8301346
--- /dev/null
+++ b/runtime/third_party/d3/src/LICENSE
@@ -0,0 +1,26 @@
+Copyright (c) 2010-2014, Michael Bostock
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+
+* The name Michael Bostock may not be used to endorse or promote products
+  derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/runtime/third_party/d3/src/README.md b/runtime/third_party/d3/src/README.md
new file mode 100644
index 0000000..eb334e2
--- /dev/null
+++ b/runtime/third_party/d3/src/README.md
@@ -0,0 +1,9 @@
+# Data-Driven Documents
+
+<a href="http://d3js.org"><img src="http://d3js.org/logo.svg" align="left" hspace="10" vspace="6"></a>
+
+**D3.js** is a JavaScript library for manipulating documents based on data. **D3** helps you bring data to life using HTML, SVG and CSS. D3’s emphasis on web standards gives you the full capabilities of modern browsers without tying yourself to a proprietary framework, combining powerful visualization components and a data-driven approach to DOM manipulation.
+
+Want to learn more? [See the wiki.](https://github.com/mbostock/d3/wiki)
+
+For examples, [see the gallery](https://github.com/mbostock/d3/wiki/Gallery) and [mbostock’s bl.ocks](http://bl.ocks.org/mbostock).
diff --git a/runtime/third_party/d3/src/d3.js b/runtime/third_party/d3/src/d3.js
new file mode 100644
index 0000000..6dcabdf
--- /dev/null
+++ b/runtime/third_party/d3/src/d3.js
@@ -0,0 +1,9297 @@
+!function() {
+  var d3 = {
+    version: "3.4.4"
+  };
+  if (!Date.now) Date.now = function() {
+    return +new Date();
+  };
+  var d3_arraySlice = [].slice, d3_array = function(list) {
+    return d3_arraySlice.call(list);
+  };
+  var d3_document = document, d3_documentElement = d3_document.documentElement, d3_window = window;
+  try {
+    d3_array(d3_documentElement.childNodes)[0].nodeType;
+  } catch (e) {
+    d3_array = function(list) {
+      var i = list.length, array = new Array(i);
+      while (i--) array[i] = list[i];
+      return array;
+    };
+  }
+  try {
+    d3_document.createElement("div").style.setProperty("opacity", 0, "");
+  } catch (error) {
+    var d3_element_prototype = d3_window.Element.prototype, d3_element_setAttribute = d3_element_prototype.setAttribute, d3_element_setAttributeNS = d3_element_prototype.setAttributeNS, d3_style_prototype = d3_window.CSSStyleDeclaration.prototype, d3_style_setProperty = d3_style_prototype.setProperty;
+    d3_element_prototype.setAttribute = function(name, value) {
+      d3_element_setAttribute.call(this, name, value + "");
+    };
+    d3_element_prototype.setAttributeNS = function(space, local, value) {
+      d3_element_setAttributeNS.call(this, space, local, value + "");
+    };
+    d3_style_prototype.setProperty = function(name, value, priority) {
+      d3_style_setProperty.call(this, name, value + "", priority);
+    };
+  }
+  d3.ascending = d3_ascending;
+  function d3_ascending(a, b) {
+    return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
+  }
+  d3.descending = function(a, b) {
+    return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
+  };
+  d3.min = function(array, f) {
+    var i = -1, n = array.length, a, b;
+    if (arguments.length === 1) {
+      while (++i < n && !((a = array[i]) != null && a <= a)) a = undefined;
+      while (++i < n) if ((b = array[i]) != null && a > b) a = b;
+    } else {
+      while (++i < n && !((a = f.call(array, array[i], i)) != null && a <= a)) a = undefined;
+      while (++i < n) if ((b = f.call(array, array[i], i)) != null && a > b) a = b;
+    }
+    return a;
+  };
+  d3.max = function(array, f) {
+    var i = -1, n = array.length, a, b;
+    if (arguments.length === 1) {
+      while (++i < n && !((a = array[i]) != null && a <= a)) a = undefined;
+      while (++i < n) if ((b = array[i]) != null && b > a) a = b;
+    } else {
+      while (++i < n && !((a = f.call(array, array[i], i)) != null && a <= a)) a = undefined;
+      while (++i < n) if ((b = f.call(array, array[i], i)) != null && b > a) a = b;
+    }
+    return a;
+  };
+  d3.extent = function(array, f) {
+    var i = -1, n = array.length, a, b, c;
+    if (arguments.length === 1) {
+      while (++i < n && !((a = c = array[i]) != null && a <= a)) a = c = undefined;
+      while (++i < n) if ((b = array[i]) != null) {
+        if (a > b) a = b;
+        if (c < b) c = b;
+      }
+    } else {
+      while (++i < n && !((a = c = f.call(array, array[i], i)) != null && a <= a)) a = undefined;
+      while (++i < n) if ((b = f.call(array, array[i], i)) != null) {
+        if (a > b) a = b;
+        if (c < b) c = b;
+      }
+    }
+    return [ a, c ];
+  };
+  d3.sum = function(array, f) {
+    var s = 0, n = array.length, a, i = -1;
+    if (arguments.length === 1) {
+      while (++i < n) if (!isNaN(a = +array[i])) s += a;
+    } else {
+      while (++i < n) if (!isNaN(a = +f.call(array, array[i], i))) s += a;
+    }
+    return s;
+  };
+  function d3_number(x) {
+    return x != null && !isNaN(x);
+  }
+  d3.mean = function(array, f) {
+    var n = array.length, a, m = 0, i = -1, j = 0;
+    if (arguments.length === 1) {
+      while (++i < n) if (d3_number(a = array[i])) m += (a - m) / ++j;
+    } else {
+      while (++i < n) if (d3_number(a = f.call(array, array[i], i))) m += (a - m) / ++j;
+    }
+    return j ? m : undefined;
+  };
+  d3.quantile = function(values, p) {
+    var H = (values.length - 1) * p + 1, h = Math.floor(H), v = +values[h - 1], e = H - h;
+    return e ? v + e * (values[h] - v) : v;
+  };
+  d3.median = function(array, f) {
+    if (arguments.length > 1) array = array.map(f);
+    array = array.filter(d3_number);
+    return array.length ? d3.quantile(array.sort(d3_ascending), .5) : undefined;
+  };
+  function d3_bisector(compare) {
+    return {
+      left: function(a, x, lo, hi) {
+        if (arguments.length < 3) lo = 0;
+        if (arguments.length < 4) hi = a.length;
+        while (lo < hi) {
+          var mid = lo + hi >>> 1;
+          if (compare(a[mid], x) < 0) lo = mid + 1; else hi = mid;
+        }
+        return lo;
+      },
+      right: function(a, x, lo, hi) {
+        if (arguments.length < 3) lo = 0;
+        if (arguments.length < 4) hi = a.length;
+        while (lo < hi) {
+          var mid = lo + hi >>> 1;
+          if (compare(a[mid], x) > 0) hi = mid; else lo = mid + 1;
+        }
+        return lo;
+      }
+    };
+  }
+  var d3_bisect = d3_bisector(d3_ascending);
+  d3.bisectLeft = d3_bisect.left;
+  d3.bisect = d3.bisectRight = d3_bisect.right;
+  d3.bisector = function(f) {
+    return d3_bisector(f.length === 1 ? function(d, x) {
+      return d3_ascending(f(d), x);
+    } : f);
+  };
+  d3.shuffle = function(array) {
+    var m = array.length, t, i;
+    while (m) {
+      i = Math.random() * m-- | 0;
+      t = array[m], array[m] = array[i], array[i] = t;
+    }
+    return array;
+  };
+  d3.permute = function(array, indexes) {
+    var i = indexes.length, permutes = new Array(i);
+    while (i--) permutes[i] = array[indexes[i]];
+    return permutes;
+  };
+  d3.pairs = function(array) {
+    var i = 0, n = array.length - 1, p0, p1 = array[0], pairs = new Array(n < 0 ? 0 : n);
+    while (i < n) pairs[i] = [ p0 = p1, p1 = array[++i] ];
+    return pairs;
+  };
+  d3.zip = function() {
+    if (!(n = arguments.length)) return [];
+    for (var i = -1, m = d3.min(arguments, d3_zipLength), zips = new Array(m); ++i < m; ) {
+      for (var j = -1, n, zip = zips[i] = new Array(n); ++j < n; ) {
+        zip[j] = arguments[j][i];
+      }
+    }
+    return zips;
+  };
+  function d3_zipLength(d) {
+    return d.length;
+  }
+  d3.transpose = function(matrix) {
+    return d3.zip.apply(d3, matrix);
+  };
+  d3.keys = function(map) {
+    var keys = [];
+    for (var key in map) keys.push(key);
+    return keys;
+  };
+  d3.values = function(map) {
+    var values = [];
+    for (var key in map) values.push(map[key]);
+    return values;
+  };
+  d3.entries = function(map) {
+    var entries = [];
+    for (var key in map) entries.push({
+      key: key,
+      value: map[key]
+    });
+    return entries;
+  };
+  d3.merge = function(arrays) {
+    var n = arrays.length, m, i = -1, j = 0, merged, array;
+    while (++i < n) j += arrays[i].length;
+    merged = new Array(j);
+    while (--n >= 0) {
+      array = arrays[n];
+      m = array.length;
+      while (--m >= 0) {
+        merged[--j] = array[m];
+      }
+    }
+    return merged;
+  };
+  var abs = Math.abs;
+  d3.range = function(start, stop, step) {
+    if (arguments.length < 3) {
+      step = 1;
+      if (arguments.length < 2) {
+        stop = start;
+        start = 0;
+      }
+    }
+    if ((stop - start) / step === Infinity) throw new Error("infinite range");
+    var range = [], k = d3_range_integerScale(abs(step)), i = -1, j;
+    start *= k, stop *= k, step *= k;
+    if (step < 0) while ((j = start + step * ++i) > stop) range.push(j / k); else while ((j = start + step * ++i) < stop) range.push(j / k);
+    return range;
+  };
+  function d3_range_integerScale(x) {
+    var k = 1;
+    while (x * k % 1) k *= 10;
+    return k;
+  }
+  function d3_class(ctor, properties) {
+    try {
+      for (var key in properties) {
+        Object.defineProperty(ctor.prototype, key, {
+          value: properties[key],
+          enumerable: false
+        });
+      }
+    } catch (e) {
+      ctor.prototype = properties;
+    }
+  }
+  d3.map = function(object) {
+    var map = new d3_Map();
+    if (object instanceof d3_Map) object.forEach(function(key, value) {
+      map.set(key, value);
+    }); else for (var key in object) map.set(key, object[key]);
+    return map;
+  };
+  function d3_Map() {}
+  d3_class(d3_Map, {
+    has: d3_map_has,
+    get: function(key) {
+      return this[d3_map_prefix + key];
+    },
+    set: function(key, value) {
+      return this[d3_map_prefix + key] = value;
+    },
+    remove: d3_map_remove,
+    keys: d3_map_keys,
+    values: function() {
+      var values = [];
+      this.forEach(function(key, value) {
+        values.push(value);
+      });
+      return values;
+    },
+    entries: function() {
+      var entries = [];
+      this.forEach(function(key, value) {
+        entries.push({
+          key: key,
+          value: value
+        });
+      });
+      return entries;
+    },
+    size: d3_map_size,
+    empty: d3_map_empty,
+    forEach: function(f) {
+      for (var key in this) if (key.charCodeAt(0) === d3_map_prefixCode) f.call(this, key.substring(1), this[key]);
+    }
+  });
+  var d3_map_prefix = "\x00", d3_map_prefixCode = d3_map_prefix.charCodeAt(0);
+  function d3_map_has(key) {
+    return d3_map_prefix + key in this;
+  }
+  function d3_map_remove(key) {
+    key = d3_map_prefix + key;
+    return key in this && delete this[key];
+  }
+  function d3_map_keys() {
+    var keys = [];
+    this.forEach(function(key) {
+      keys.push(key);
+    });
+    return keys;
+  }
+  function d3_map_size() {
+    var size = 0;
+    for (var key in this) if (key.charCodeAt(0) === d3_map_prefixCode) ++size;
+    return size;
+  }
+  function d3_map_empty() {
+    for (var key in this) if (key.charCodeAt(0) === d3_map_prefixCode) return false;
+    return true;
+  }
+  d3.nest = function() {
+    var nest = {}, keys = [], sortKeys = [], sortValues, rollup;
+    function map(mapType, array, depth) {
+      if (depth >= keys.length) return rollup ? rollup.call(nest, array) : sortValues ? array.sort(sortValues) : array;
+      var i = -1, n = array.length, key = keys[depth++], keyValue, object, setter, valuesByKey = new d3_Map(), values;
+      while (++i < n) {
+        if (values = valuesByKey.get(keyValue = key(object = array[i]))) {
+          values.push(object);
+        } else {
+          valuesByKey.set(keyValue, [ object ]);
+        }
+      }
+      if (mapType) {
+        object = mapType();
+        setter = function(keyValue, values) {
+          object.set(keyValue, map(mapType, values, depth));
+        };
+      } else {
+        object = {};
+        setter = function(keyValue, values) {
+          object[keyValue] = map(mapType, values, depth);
+        };
+      }
+      valuesByKey.forEach(setter);
+      return object;
+    }
+    function entries(map, depth) {
+      if (depth >= keys.length) return map;
+      var array = [], sortKey = sortKeys[depth++];
+      map.forEach(function(key, keyMap) {
+        array.push({
+          key: key,
+          values: entries(keyMap, depth)
+        });
+      });
+      return sortKey ? array.sort(function(a, b) {
+        return sortKey(a.key, b.key);
+      }) : array;
+    }
+    nest.map = function(array, mapType) {
+      return map(mapType, array, 0);
+    };
+    nest.entries = function(array) {
+      return entries(map(d3.map, array, 0), 0);
+    };
+    nest.key = function(d) {
+      keys.push(d);
+      return nest;
+    };
+    nest.sortKeys = function(order) {
+      sortKeys[keys.length - 1] = order;
+      return nest;
+    };
+    nest.sortValues = function(order) {
+      sortValues = order;
+      return nest;
+    };
+    nest.rollup = function(f) {
+      rollup = f;
+      return nest;
+    };
+    return nest;
+  };
+  d3.set = function(array) {
+    var set = new d3_Set();
+    if (array) for (var i = 0, n = array.length; i < n; ++i) set.add(array[i]);
+    return set;
+  };
+  function d3_Set() {}
+  d3_class(d3_Set, {
+    has: d3_map_has,
+    add: function(value) {
+      this[d3_map_prefix + value] = true;
+      return value;
+    },
+    remove: function(value) {
+      value = d3_map_prefix + value;
+      return value in this && delete this[value];
+    },
+    values: d3_map_keys,
+    size: d3_map_size,
+    empty: d3_map_empty,
+    forEach: function(f) {
+      for (var value in this) if (value.charCodeAt(0) === d3_map_prefixCode) f.call(this, value.substring(1));
+    }
+  });
+  d3.behavior = {};
+  d3.rebind = function(target, source) {
+    var i = 1, n = arguments.length, method;
+    while (++i < n) target[method = arguments[i]] = d3_rebind(target, source, source[method]);
+    return target;
+  };
+  function d3_rebind(target, source, method) {
+    return function() {
+      var value = method.apply(source, arguments);
+      return value === source ? target : value;
+    };
+  }
+  function d3_vendorSymbol(object, name) {
+    if (name in object) return name;
+    name = name.charAt(0).toUpperCase() + name.substring(1);
+    for (var i = 0, n = d3_vendorPrefixes.length; i < n; ++i) {
+      var prefixName = d3_vendorPrefixes[i] + name;
+      if (prefixName in object) return prefixName;
+    }
+  }
+  var d3_vendorPrefixes = [ "webkit", "ms", "moz", "Moz", "o", "O" ];
+  function d3_noop() {}
+  d3.dispatch = function() {
+    var dispatch = new d3_dispatch(), i = -1, n = arguments.length;
+    while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch);
+    return dispatch;
+  };
+  function d3_dispatch() {}
+  d3_dispatch.prototype.on = function(type, listener) {
+    var i = type.indexOf("."), name = "";
+    if (i >= 0) {
+      name = type.substring(i + 1);
+      type = type.substring(0, i);
+    }
+    if (type) return arguments.length < 2 ? this[type].on(name) : this[type].on(name, listener);
+    if (arguments.length === 2) {
+      if (listener == null) for (type in this) {
+        if (this.hasOwnProperty(type)) this[type].on(name, null);
+      }
+      return this;
+    }
+  };
+  function d3_dispatch_event(dispatch) {
+    var listeners = [], listenerByName = new d3_Map();
+    function event() {
+      var z = listeners, i = -1, n = z.length, l;
+      while (++i < n) if (l = z[i].on) l.apply(this, arguments);
+      return dispatch;
+    }
+    event.on = function(name, listener) {
+      var l = listenerByName.get(name), i;
+      if (arguments.length < 2) return l && l.on;
+      if (l) {
+        l.on = null;
+        listeners = listeners.slice(0, i = listeners.indexOf(l)).concat(listeners.slice(i + 1));
+        listenerByName.remove(name);
+      }
+      if (listener) listeners.push(listenerByName.set(name, {
+        on: listener
+      }));
+      return dispatch;
+    };
+    return event;
+  }
+  d3.event = null;
+  function d3_eventPreventDefault() {
+    d3.event.preventDefault();
+  }
+  function d3_eventSource() {
+    var e = d3.event, s;
+    while (s = e.sourceEvent) e = s;
+    return e;
+  }
+  function d3_eventDispatch(target) {
+    var dispatch = new d3_dispatch(), i = 0, n = arguments.length;
+    while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch);
+    dispatch.of = function(thiz, argumentz) {
+      return function(e1) {
+        try {
+          var e0 = e1.sourceEvent = d3.event;
+          e1.target = target;
+          d3.event = e1;
+          dispatch[e1.type].apply(thiz, argumentz);
+        } finally {
+          d3.event = e0;
+        }
+      };
+    };
+    return dispatch;
+  }
+  d3.requote = function(s) {
+    return s.replace(d3_requote_re, "\\$&");
+  };
+  var d3_requote_re = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;
+  var d3_subclass = {}.__proto__ ? function(object, prototype) {
+    object.__proto__ = prototype;
+  } : function(object, prototype) {
+    for (var property in prototype) object[property] = prototype[property];
+  };
+  function d3_selection(groups) {
+    d3_subclass(groups, d3_selectionPrototype);
+    return groups;
+  }
+  var d3_select = function(s, n) {
+    return n.querySelector(s);
+  }, d3_selectAll = function(s, n) {
+    return n.querySelectorAll(s);
+  }, d3_selectMatcher = d3_documentElement[d3_vendorSymbol(d3_documentElement, "matchesSelector")], d3_selectMatches = function(n, s) {
+    return d3_selectMatcher.call(n, s);
+  };
+  if (typeof Sizzle === "function") {
+    d3_select = function(s, n) {
+      return Sizzle(s, n)[0] || null;
+    };
+    d3_selectAll = Sizzle;
+    d3_selectMatches = Sizzle.matchesSelector;
+  }
+  d3.selection = function() {
+    return d3_selectionRoot;
+  };
+  var d3_selectionPrototype = d3.selection.prototype = [];
+  d3_selectionPrototype.select = function(selector) {
+    var subgroups = [], subgroup, subnode, group, node;
+    selector = d3_selection_selector(selector);
+    for (var j = -1, m = this.length; ++j < m; ) {
+      subgroups.push(subgroup = []);
+      subgroup.parentNode = (group = this[j]).parentNode;
+      for (var i = -1, n = group.length; ++i < n; ) {
+        if (node = group[i]) {
+          subgroup.push(subnode = selector.call(node, node.__data__, i, j));
+          if (subnode && "__data__" in node) subnode.__data__ = node.__data__;
+        } else {
+          subgroup.push(null);
+        }
+      }
+    }
+    return d3_selection(subgroups);
+  };
+  function d3_selection_selector(selector) {
+    return typeof selector === "function" ? selector : function() {
+      return d3_select(selector, this);
+    };
+  }
+  d3_selectionPrototype.selectAll = function(selector) {
+    var subgroups = [], subgroup, node;
+    selector = d3_selection_selectorAll(selector);
+    for (var j = -1, m = this.length; ++j < m; ) {
+      for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
+        if (node = group[i]) {
+          subgroups.push(subgroup = d3_array(selector.call(node, node.__data__, i, j)));
+          subgroup.parentNode = node;
+        }
+      }
+    }
+    return d3_selection(subgroups);
+  };
+  function d3_selection_selectorAll(selector) {
+    return typeof selector === "function" ? selector : function() {
+      return d3_selectAll(selector, this);
+    };
+  }
+  var d3_nsPrefix = {
+    svg: "http://www.w3.org/2000/svg",
+    xhtml: "http://www.w3.org/1999/xhtml",
+    xlink: "http://www.w3.org/1999/xlink",
+    xml: "http://www.w3.org/XML/1998/namespace",
+    xmlns: "http://www.w3.org/2000/xmlns/"
+  };
+  d3.ns = {
+    prefix: d3_nsPrefix,
+    qualify: function(name) {
+      var i = name.indexOf(":"), prefix = name;
+      if (i >= 0) {
+        prefix = name.substring(0, i);
+        name = name.substring(i + 1);
+      }
+      return d3_nsPrefix.hasOwnProperty(prefix) ? {
+        space: d3_nsPrefix[prefix],
+        local: name
+      } : name;
+    }
+  };
+  d3_selectionPrototype.attr = function(name, value) {
+    if (arguments.length < 2) {
+      if (typeof name === "string") {
+        var node = this.node();
+        name = d3.ns.qualify(name);
+        return name.local ? node.getAttributeNS(name.space, name.local) : node.getAttribute(name);
+      }
+      for (value in name) this.each(d3_selection_attr(value, name[value]));
+      return this;
+    }
+    return this.each(d3_selection_attr(name, value));
+  };
+  function d3_selection_attr(name, value) {
+    name = d3.ns.qualify(name);
+    function attrNull() {
+      this.removeAttribute(name);
+    }
+    function attrNullNS() {
+      this.removeAttributeNS(name.space, name.local);
+    }
+    function attrConstant() {
+      this.setAttribute(name, value);
+    }
+    function attrConstantNS() {
+      this.setAttributeNS(name.space, name.local, value);
+    }
+    function attrFunction() {
+      var x = value.apply(this, arguments);
+      if (x == null) this.removeAttribute(name); else this.setAttribute(name, x);
+    }
+    function attrFunctionNS() {
+      var x = value.apply(this, arguments);
+      if (x == null) this.removeAttributeNS(name.space, name.local); else this.setAttributeNS(name.space, name.local, x);
+    }
+    return value == null ? name.local ? attrNullNS : attrNull : typeof value === "function" ? name.local ? attrFunctionNS : attrFunction : name.local ? attrConstantNS : attrConstant;
+  }
+  function d3_collapse(s) {
+    return s.trim().replace(/\s+/g, " ");
+  }
+  d3_selectionPrototype.classed = function(name, value) {
+    if (arguments.length < 2) {
+      if (typeof name === "string") {
+        var node = this.node(), n = (name = d3_selection_classes(name)).length, i = -1;
+        if (value = node.classList) {
+          while (++i < n) if (!value.contains(name[i])) return false;
+        } else {
+          value = node.getAttribute("class");
+          while (++i < n) if (!d3_selection_classedRe(name[i]).test(value)) return false;
+        }
+        return true;
+      }
+      for (value in name) this.each(d3_selection_classed(value, name[value]));
+      return this;
+    }
+    return this.each(d3_selection_classed(name, value));
+  };
+  function d3_selection_classedRe(name) {
+    return new RegExp("(?:^|\\s+)" + d3.requote(name) + "(?:\\s+|$)", "g");
+  }
+  function d3_selection_classes(name) {
+    return name.trim().split(/^|\s+/);
+  }
+  function d3_selection_classed(name, value) {
+    name = d3_selection_classes(name).map(d3_selection_classedName);
+    var n = name.length;
+    function classedConstant() {
+      var i = -1;
+      while (++i < n) name[i](this, value);
+    }
+    function classedFunction() {
+      var i = -1, x = value.apply(this, arguments);
+      while (++i < n) name[i](this, x);
+    }
+    return typeof value === "function" ? classedFunction : classedConstant;
+  }
+  function d3_selection_classedName(name) {
+    var re = d3_selection_classedRe(name);
+    return function(node, value) {
+      if (c = node.classList) return value ? c.add(name) : c.remove(name);
+      var c = node.getAttribute("class") || "";
+      if (value) {
+        re.lastIndex = 0;
+        if (!re.test(c)) node.setAttribute("class", d3_collapse(c + " " + name));
+      } else {
+        node.setAttribute("class", d3_collapse(c.replace(re, " ")));
+      }
+    };
+  }
+  d3_selectionPrototype.style = function(name, value, priority) {
+    var n = arguments.length;
+    if (n < 3) {
+      if (typeof name !== "string") {
+        if (n < 2) value = "";
+        for (priority in name) this.each(d3_selection_style(priority, name[priority], value));
+        return this;
+      }
+      if (n < 2) return d3_window.getComputedStyle(this.node(), null).getPropertyValue(name);
+      priority = "";
+    }
+    return this.each(d3_selection_style(name, value, priority));
+  };
+  function d3_selection_style(name, value, priority) {
+    function styleNull() {
+      this.style.removeProperty(name);
+    }
+    function styleConstant() {
+      this.style.setProperty(name, value, priority);
+    }
+    function styleFunction() {
+      var x = value.apply(this, arguments);
+      if (x == null) this.style.removeProperty(name); else this.style.setProperty(name, x, priority);
+    }
+    return value == null ? styleNull : typeof value === "function" ? styleFunction : styleConstant;
+  }
+  d3_selectionPrototype.property = function(name, value) {
+    if (arguments.length < 2) {
+      if (typeof name === "string") return this.node()[name];
+      for (value in name) this.each(d3_selection_property(value, name[value]));
+      return this;
+    }
+    return this.each(d3_selection_property(name, value));
+  };
+  function d3_selection_property(name, value) {
+    function propertyNull() {
+      delete this[name];
+    }
+    function propertyConstant() {
+      this[name] = value;
+    }
+    function propertyFunction() {
+      var x = value.apply(this, arguments);
+      if (x == null) delete this[name]; else this[name] = x;
+    }
+    return value == null ? propertyNull : typeof value === "function" ? propertyFunction : propertyConstant;
+  }
+  d3_selectionPrototype.text = function(value) {
+    return arguments.length ? this.each(typeof value === "function" ? function() {
+      var v = value.apply(this, arguments);
+      this.textContent = v == null ? "" : v;
+    } : value == null ? function() {
+      this.textContent = "";
+    } : function() {
+      this.textContent = value;
+    }) : this.node().textContent;
+  };
+  d3_selectionPrototype.html = function(value) {
+    throw "disallowed by chromium security";
+    return arguments.length ? this.each(typeof value === "function" ? function() {
+      var v = value.apply(this, arguments);
+      this.innerHTML = v == null ? "" : v;
+    } : value == null ? function() {
+      this.innerHTML = "";
+    } : function() {
+      this.innerHTML = value;
+    }) : this.node().innerHTML;
+  };
+  d3_selectionPrototype.append = function(name) {
+    name = d3_selection_creator(name);
+    return this.select(function() {
+      return this.appendChild(name.apply(this, arguments));
+    });
+  };
+  function d3_selection_creator(name) {
+    return typeof name === "function" ? name : (name = d3.ns.qualify(name)).local ? function() {
+      return this.ownerDocument.createElementNS(name.space, name.local);
+    } : function() {
+      return this.ownerDocument.createElementNS(this.namespaceURI, name);
+    };
+  }
+  d3_selectionPrototype.insert = function(name, before) {
+    name = d3_selection_creator(name);
+    before = d3_selection_selector(before);
+    return this.select(function() {
+      return this.insertBefore(name.apply(this, arguments), before.apply(this, arguments) || null);
+    });
+  };
+  d3_selectionPrototype.remove = function() {
+    return this.each(function() {
+      var parent = this.parentNode;
+      if (parent) parent.removeChild(this);
+    });
+  };
+  d3_selectionPrototype.data = function(value, key) {
+    var i = -1, n = this.length, group, node;
+    if (!arguments.length) {
+      value = new Array(n = (group = this[0]).length);
+      while (++i < n) {
+        if (node = group[i]) {
+          value[i] = node.__data__;
+        }
+      }
+      return value;
+    }
+    function bind(group, groupData) {
+      var i, n = group.length, m = groupData.length, n0 = Math.min(n, m), updateNodes = new Array(m), enterNodes = new Array(m), exitNodes = new Array(n), node, nodeData;
+      if (key) {
+        var nodeByKeyValue = new d3_Map(), dataByKeyValue = new d3_Map(), keyValues = [], keyValue;
+        for (i = -1; ++i < n; ) {
+          keyValue = key.call(node = group[i], node.__data__, i);
+          if (nodeByKeyValue.has(keyValue)) {
+            exitNodes[i] = node;
+          } else {
+            nodeByKeyValue.set(keyValue, node);
+          }
+          keyValues.push(keyValue);
+        }
+        for (i = -1; ++i < m; ) {
+          keyValue = key.call(groupData, nodeData = groupData[i], i);
+          if (node = nodeByKeyValue.get(keyValue)) {
+            updateNodes[i] = node;
+            node.__data__ = nodeData;
+          } else if (!dataByKeyValue.has(keyValue)) {
+            enterNodes[i] = d3_selection_dataNode(nodeData);
+          }
+          dataByKeyValue.set(keyValue, nodeData);
+          nodeByKeyValue.remove(keyValue);
+        }
+        for (i = -1; ++i < n; ) {
+          if (nodeByKeyValue.has(keyValues[i])) {
+            exitNodes[i] = group[i];
+          }
+        }
+      } else {
+        for (i = -1; ++i < n0; ) {
+          node = group[i];
+          nodeData = groupData[i];
+          if (node) {
+            node.__data__ = nodeData;
+            updateNodes[i] = node;
+          } else {
+            enterNodes[i] = d3_selection_dataNode(nodeData);
+          }
+        }
+        for (;i < m; ++i) {
+          enterNodes[i] = d3_selection_dataNode(groupData[i]);
+        }
+        for (;i < n; ++i) {
+          exitNodes[i] = group[i];
+        }
+      }
+      enterNodes.update = updateNodes;
+      enterNodes.parentNode = updateNodes.parentNode = exitNodes.parentNode = group.parentNode;
+      enter.push(enterNodes);
+      update.push(updateNodes);
+      exit.push(exitNodes);
+    }
+    var enter = d3_selection_enter([]), update = d3_selection([]), exit = d3_selection([]);
+    if (typeof value === "function") {
+      while (++i < n) {
+        bind(group = this[i], value.call(group, group.parentNode.__data__, i));
+      }
+    } else {
+      while (++i < n) {
+        bind(group = this[i], value);
+      }
+    }
+    update.enter = function() {
+      return enter;
+    };
+    update.exit = function() {
+      return exit;
+    };
+    return update;
+  };
+  function d3_selection_dataNode(data) {
+    return {
+      __data__: data
+    };
+  }
+  d3_selectionPrototype.datum = function(value) {
+    return arguments.length ? this.property("__data__", value) : this.property("__data__");
+  };
+  d3_selectionPrototype.filter = function(filter) {
+    var subgroups = [], subgroup, group, node;
+    if (typeof filter !== "function") filter = d3_selection_filter(filter);
+    for (var j = 0, m = this.length; j < m; j++) {
+      subgroups.push(subgroup = []);
+      subgroup.parentNode = (group = this[j]).parentNode;
+      for (var i = 0, n = group.length; i < n; i++) {
+        if ((node = group[i]) && filter.call(node, node.__data__, i, j)) {
+          subgroup.push(node);
+        }
+      }
+    }
+    return d3_selection(subgroups);
+  };
+  function d3_selection_filter(selector) {
+    return function() {
+      return d3_selectMatches(this, selector);
+    };
+  }
+  d3_selectionPrototype.order = function() {
+    for (var j = -1, m = this.length; ++j < m; ) {
+      for (var group = this[j], i = group.length - 1, next = group[i], node; --i >= 0; ) {
+        if (node = group[i]) {
+          if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next);
+          next = node;
+        }
+      }
+    }
+    return this;
+  };
+  d3_selectionPrototype.sort = function(comparator) {
+    comparator = d3_selection_sortComparator.apply(this, arguments);
+    for (var j = -1, m = this.length; ++j < m; ) this[j].sort(comparator);
+    return this.order();
+  };
+  function d3_selection_sortComparator(comparator) {
+    if (!arguments.length) comparator = d3_ascending;
+    return function(a, b) {
+      return a && b ? comparator(a.__data__, b.__data__) : !a - !b;
+    };
+  }
+  d3_selectionPrototype.each = function(callback) {
+    return d3_selection_each(this, function(node, i, j) {
+      callback.call(node, node.__data__, i, j);
+    });
+  };
+  function d3_selection_each(groups, callback) {
+    for (var j = 0, m = groups.length; j < m; j++) {
+      for (var group = groups[j], i = 0, n = group.length, node; i < n; i++) {
+        if (node = group[i]) callback(node, i, j);
+      }
+    }
+    return groups;
+  }
+  d3_selectionPrototype.call = function(callback) {
+    var args = d3_array(arguments);
+    callback.apply(args[0] = this, args);
+    return this;
+  };
+  d3_selectionPrototype.empty = function() {
+    return !this.node();
+  };
+  d3_selectionPrototype.node = function() {
+    for (var j = 0, m = this.length; j < m; j++) {
+      for (var group = this[j], i = 0, n = group.length; i < n; i++) {
+        var node = group[i];
+        if (node) return node;
+      }
+    }
+    return null;
+  };
+  d3_selectionPrototype.size = function() {
+    var n = 0;
+    this.each(function() {
+      ++n;
+    });
+    return n;
+  };
+  function d3_selection_enter(selection) {
+    d3_subclass(selection, d3_selection_enterPrototype);
+    return selection;
+  }
+  var d3_selection_enterPrototype = [];
+  d3.selection.enter = d3_selection_enter;
+  d3.selection.enter.prototype = d3_selection_enterPrototype;
+  d3_selection_enterPrototype.append = d3_selectionPrototype.append;
+  d3_selection_enterPrototype.empty = d3_selectionPrototype.empty;
+  d3_selection_enterPrototype.node = d3_selectionPrototype.node;
+  d3_selection_enterPrototype.call = d3_selectionPrototype.call;
+  d3_selection_enterPrototype.size = d3_selectionPrototype.size;
+  d3_selection_enterPrototype.select = function(selector) {
+    var subgroups = [], subgroup, subnode, upgroup, group, node;
+    for (var j = -1, m = this.length; ++j < m; ) {
+      upgroup = (group = this[j]).update;
+      subgroups.push(subgroup = []);
+      subgroup.parentNode = group.parentNode;
+      for (var i = -1, n = group.length; ++i < n; ) {
+        if (node = group[i]) {
+          subgroup.push(upgroup[i] = subnode = selector.call(group.parentNode, node.__data__, i, j));
+          subnode.__data__ = node.__data__;
+        } else {
+          subgroup.push(null);
+        }
+      }
+    }
+    return d3_selection(subgroups);
+  };
+  d3_selection_enterPrototype.insert = function(name, before) {
+    if (arguments.length < 2) before = d3_selection_enterInsertBefore(this);
+    return d3_selectionPrototype.insert.call(this, name, before);
+  };
+  function d3_selection_enterInsertBefore(enter) {
+    var i0, j0;
+    return function(d, i, j) {
+      var group = enter[j].update, n = group.length, node;
+      if (j != j0) j0 = j, i0 = 0;
+      if (i >= i0) i0 = i + 1;
+      while (!(node = group[i0]) && ++i0 < n) ;
+      return node;
+    };
+  }
+  d3_selectionPrototype.transition = function() {
+    var id = d3_transitionInheritId || ++d3_transitionId, subgroups = [], subgroup, node, transition = d3_transitionInherit || {
+      time: Date.now(),
+      ease: d3_ease_cubicInOut,
+      delay: 0,
+      duration: 250
+    };
+    for (var j = -1, m = this.length; ++j < m; ) {
+      subgroups.push(subgroup = []);
+      for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
+        if (node = group[i]) d3_transitionNode(node, i, id, transition);
+        subgroup.push(node);
+      }
+    }
+    return d3_transition(subgroups, id);
+  };
+  d3_selectionPrototype.interrupt = function() {
+    return this.each(d3_selection_interrupt);
+  };
+  function d3_selection_interrupt() {
+    var lock = this.__transition__;
+    if (lock) ++lock.active;
+  }
+  d3.select = function(node) {
+    var group = [ typeof node === "string" ? d3_select(node, d3_document) : node ];
+    group.parentNode = d3_documentElement;
+    return d3_selection([ group ]);
+  };
+  d3.selectAll = function(nodes) {
+    var group = d3_array(typeof nodes === "string" ? d3_selectAll(nodes, d3_document) : nodes);
+    group.parentNode = d3_documentElement;
+    return d3_selection([ group ]);
+  };
+  var d3_selectionRoot = d3.select(d3_documentElement);
+  d3_selectionPrototype.on = function(type, listener, capture) {
+    var n = arguments.length;
+    if (n < 3) {
+      if (typeof type !== "string") {
+        if (n < 2) listener = false;
+        for (capture in type) this.each(d3_selection_on(capture, type[capture], listener));
+        return this;
+      }
+      if (n < 2) return (n = this.node()["__on" + type]) && n._;
+      capture = false;
+    }
+    return this.each(d3_selection_on(type, listener, capture));
+  };
+  function d3_selection_on(type, listener, capture) {
+    var name = "__on" + type, i = type.indexOf("."), wrap = d3_selection_onListener;
+    if (i > 0) type = type.substring(0, i);
+    var filter = d3_selection_onFilters.get(type);
+    if (filter) type = filter, wrap = d3_selection_onFilter;
+    function onRemove() {
+      var l = this[name];
+      if (l) {
+        this.removeEventListener(type, l, l.$);
+        delete this[name];
+      }
+    }
+    function onAdd() {
+      var l = wrap(listener, d3_array(arguments));
+      onRemove.call(this);
+      this.addEventListener(type, this[name] = l, l.$ = capture);
+      l._ = listener;
+    }
+    function removeAll() {
+      var re = new RegExp("^__on([^.]+)" + d3.requote(type) + "$"), match;
+      for (var name in this) {
+        if (match = name.match(re)) {
+          var l = this[name];
+          this.removeEventListener(match[1], l, l.$);
+          delete this[name];
+        }
+      }
+    }
+    return i ? listener ? onAdd : onRemove : listener ? d3_noop : removeAll;
+  }
+  var d3_selection_onFilters = d3.map({
+    mouseenter: "mouseover",
+    mouseleave: "mouseout"
+  });
+  d3_selection_onFilters.forEach(function(k) {
+    if ("on" + k in d3_document) d3_selection_onFilters.remove(k);
+  });
+  function d3_selection_onListener(listener, argumentz) {
+    return function(e) {
+      var o = d3.event;
+      d3.event = e;
+      argumentz[0] = this.__data__;
+      try {
+        listener.apply(this, argumentz);
+      } finally {
+        d3.event = o;
+      }
+    };
+  }
+  function d3_selection_onFilter(listener, argumentz) {
+    var l = d3_selection_onListener(listener, argumentz);
+    return function(e) {
+      var target = this, related = e.relatedTarget;
+      if (!related || related !== target && !(related.compareDocumentPosition(target) & 8)) {
+        l.call(target, e);
+      }
+    };
+  }
+  var d3_event_dragSelect = "onselectstart" in d3_document ? null : d3_vendorSymbol(d3_documentElement.style, "userSelect"), d3_event_dragId = 0;
+  function d3_event_dragSuppress() {
+    var name = ".dragsuppress-" + ++d3_event_dragId, click = "click" + name, w = d3.select(d3_window).on("touchmove" + name, d3_eventPreventDefault).on("dragstart" + name, d3_eventPreventDefault).on("selectstart" + name, d3_eventPreventDefault);
+    if (d3_event_dragSelect) {
+      var style = d3_documentElement.style, select = style[d3_event_dragSelect];
+      style[d3_event_dragSelect] = "none";
+    }
+    return function(suppressClick) {
+      w.on(name, null);
+      if (d3_event_dragSelect) style[d3_event_dragSelect] = select;
+      if (suppressClick) {
+        function off() {
+          w.on(click, null);
+        }
+        w.on(click, function() {
+          d3_eventPreventDefault();
+          off();
+        }, true);
+        setTimeout(off, 0);
+      }
+    };
+  }
+  d3.mouse = function(container) {
+    return d3_mousePoint(container, d3_eventSource());
+  };
+  function d3_mousePoint(container, e) {
+    if (e.changedTouches) e = e.changedTouches[0];
+    var svg = container.ownerSVGElement || container;
+    if (svg.createSVGPoint) {
+      var point = svg.createSVGPoint();
+      point.x = e.clientX, point.y = e.clientY;
+      point = point.matrixTransform(container.getScreenCTM().inverse());
+      return [ point.x, point.y ];
+    }
+    var rect = container.getBoundingClientRect();
+    return [ e.clientX - rect.left - container.clientLeft, e.clientY - rect.top - container.clientTop ];
+  }
+  d3.touches = function(container, touches) {
+    if (arguments.length < 2) touches = d3_eventSource().touches;
+    return touches ? d3_array(touches).map(function(touch) {
+      var point = d3_mousePoint(container, touch);
+      point.identifier = touch.identifier;
+      return point;
+    }) : [];
+  };
+  d3.behavior.drag = function() {
+    var event = d3_eventDispatch(drag, "drag", "dragstart", "dragend"), origin = null, mousedown = dragstart(d3_noop, d3.mouse, d3_behavior_dragMouseSubject, "mousemove", "mouseup"), touchstart = dragstart(d3_behavior_dragTouchId, d3.touch, d3_behavior_dragTouchSubject, "touchmove", "touchend");
+    function drag() {
+      this.on("mousedown.drag", mousedown).on("touchstart.drag", touchstart);
+    }
+    function dragstart(id, position, subject, move, end) {
+      return function() {
+        var that = this, target = d3.event.target, parent = that.parentNode, dispatch = event.of(that, arguments), dragged = 0, dragId = id(), dragName = ".drag" + (dragId == null ? "" : "-" + dragId), dragOffset, dragSubject = d3.select(subject()).on(move + dragName, moved).on(end + dragName, ended), dragRestore = d3_event_dragSuppress(), position0 = position(parent, dragId);
+        if (origin) {
+          dragOffset = origin.apply(that, arguments);
+          dragOffset = [ dragOffset.x - position0[0], dragOffset.y - position0[1] ];
+        } else {
+          dragOffset = [ 0, 0 ];
+        }
+        dispatch({
+          type: "dragstart"
+        });
+        function moved() {
+          var position1 = position(parent, dragId), dx, dy;
+          if (!position1) return;
+          dx = position1[0] - position0[0];
+          dy = position1[1] - position0[1];
+          dragged |= dx | dy;
+          position0 = position1;
+          dispatch({
+            type: "drag",
+            x: position1[0] + dragOffset[0],
+            y: position1[1] + dragOffset[1],
+            dx: dx,
+            dy: dy
+          });
+        }
+        function ended() {
+          if (!position(parent, dragId)) return;
+          dragSubject.on(move + dragName, null).on(end + dragName, null);
+          dragRestore(dragged && d3.event.target === target);
+          dispatch({
+            type: "dragend"
+          });
+        }
+      };
+    }
+    drag.origin = function(x) {
+      if (!arguments.length) return origin;
+      origin = x;
+      return drag;
+    };
+    return d3.rebind(drag, event, "on");
+  };
+  function d3_behavior_dragTouchId() {
+    return d3.event.changedTouches[0].identifier;
+  }
+  function d3_behavior_dragTouchSubject() {
+    return d3.event.target;
+  }
+  function d3_behavior_dragMouseSubject() {
+    return d3_window;
+  }
+  var π = Math.PI, τ = 2 * π, halfπ = π / 2, ε = 1e-6, ε2 = ε * ε, d3_radians = π / 180, d3_degrees = 180 / π;
+  function d3_sgn(x) {
+    return x > 0 ? 1 : x < 0 ? -1 : 0;
+  }
+  function d3_cross2d(a, b, c) {
+    return (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]);
+  }
+  function d3_acos(x) {
+    return x > 1 ? 0 : x < -1 ? π : Math.acos(x);
+  }
+  function d3_asin(x) {
+    return x > 1 ? halfπ : x < -1 ? -halfπ : Math.asin(x);
+  }
+  function d3_sinh(x) {
+    return ((x = Math.exp(x)) - 1 / x) / 2;
+  }
+  function d3_cosh(x) {
+    return ((x = Math.exp(x)) + 1 / x) / 2;
+  }
+  function d3_tanh(x) {
+    return ((x = Math.exp(2 * x)) - 1) / (x + 1);
+  }
+  function d3_haversin(x) {
+    return (x = Math.sin(x / 2)) * x;
+  }
+  var ρ = Math.SQRT2, ρ2 = 2, ρ4 = 4;
+  d3.interpolateZoom = function(p0, p1) {
+    var ux0 = p0[0], uy0 = p0[1], w0 = p0[2], ux1 = p1[0], uy1 = p1[1], w1 = p1[2];
+    var dx = ux1 - ux0, dy = uy1 - uy0, d2 = dx * dx + dy * dy, d1 = Math.sqrt(d2), b0 = (w1 * w1 - w0 * w0 + ρ4 * d2) / (2 * w0 * ρ2 * d1), b1 = (w1 * w1 - w0 * w0 - ρ4 * d2) / (2 * w1 * ρ2 * d1), r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0), r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1), dr = r1 - r0, S = (dr || Math.log(w1 / w0)) / ρ;
+    function interpolate(t) {
+      var s = t * S;
+      if (dr) {
+        var coshr0 = d3_cosh(r0), u = w0 / (ρ2 * d1) * (coshr0 * d3_tanh(ρ * s + r0) - d3_sinh(r0));
+        return [ ux0 + u * dx, uy0 + u * dy, w0 * coshr0 / d3_cosh(ρ * s + r0) ];
+      }
+      return [ ux0 + t * dx, uy0 + t * dy, w0 * Math.exp(ρ * s) ];
+    }
+    interpolate.duration = S * 1e3;
+    return interpolate;
+  };
+  d3.behavior.zoom = function() {
+    var view = {
+      x: 0,
+      y: 0,
+      k: 1
+    }, translate0, center, size = [ 960, 500 ], scaleExtent = d3_behavior_zoomInfinity, mousedown = "mousedown.zoom", mousemove = "mousemove.zoom", mouseup = "mouseup.zoom", mousewheelTimer, touchstart = "touchstart.zoom", touchtime, event = d3_eventDispatch(zoom, "zoomstart", "zoom", "zoomend"), x0, x1, y0, y1;
+    function zoom(g) {
+      g.on(mousedown, mousedowned).on(d3_behavior_zoomWheel + ".zoom", mousewheeled).on(mousemove, mousewheelreset).on("dblclick.zoom", dblclicked).on(touchstart, touchstarted);
+    }
+    zoom.event = function(g) {
+      g.each(function() {
+        var dispatch = event.of(this, arguments), view1 = view;
+        if (d3_transitionInheritId) {
+          d3.select(this).transition().each("start.zoom", function() {
+            view = this.__chart__ || {
+              x: 0,
+              y: 0,
+              k: 1
+            };
+            zoomstarted(dispatch);
+          }).tween("zoom:zoom", function() {
+            var dx = size[0], dy = size[1], cx = dx / 2, cy = dy / 2, i = d3.interpolateZoom([ (cx - view.x) / view.k, (cy - view.y) / view.k, dx / view.k ], [ (cx - view1.x) / view1.k, (cy - view1.y) / view1.k, dx / view1.k ]);
+            return function(t) {
+              var l = i(t), k = dx / l[2];
+              this.__chart__ = view = {
+                x: cx - l[0] * k,
+                y: cy - l[1] * k,
+                k: k
+              };
+              zoomed(dispatch);
+            };
+          }).each("end.zoom", function() {
+            zoomended(dispatch);
+          });
+        } else {
+          this.__chart__ = view;
+          zoomstarted(dispatch);
+          zoomed(dispatch);
+          zoomended(dispatch);
+        }
+      });
+    };
+    zoom.translate = function(_) {
+      if (!arguments.length) return [ view.x, view.y ];
+      view = {
+        x: +_[0],
+        y: +_[1],
+        k: view.k
+      };
+      rescale();
+      return zoom;
+    };
+    zoom.scale = function(_) {
+      if (!arguments.length) return view.k;
+      view = {
+        x: view.x,
+        y: view.y,
+        k: +_
+      };
+      rescale();
+      return zoom;
+    };
+    zoom.scaleExtent = function(_) {
+      if (!arguments.length) return scaleExtent;
+      scaleExtent = _ == null ? d3_behavior_zoomInfinity : [ +_[0], +_[1] ];
+      return zoom;
+    };
+    zoom.center = function(_) {
+      if (!arguments.length) return center;
+      center = _ && [ +_[0], +_[1] ];
+      return zoom;
+    };
+    zoom.size = function(_) {
+      if (!arguments.length) return size;
+      size = _ && [ +_[0], +_[1] ];
+      return zoom;
+    };
+    zoom.x = function(z) {
+      if (!arguments.length) return x1;
+      x1 = z;
+      x0 = z.copy();
+      view = {
+        x: 0,
+        y: 0,
+        k: 1
+      };
+      return zoom;
+    };
+    zoom.y = function(z) {
+      if (!arguments.length) return y1;
+      y1 = z;
+      y0 = z.copy();
+      view = {
+        x: 0,
+        y: 0,
+        k: 1
+      };
+      return zoom;
+    };
+    function location(p) {
+      return [ (p[0] - view.x) / view.k, (p[1] - view.y) / view.k ];
+    }
+    function point(l) {
+      return [ l[0] * view.k + view.x, l[1] * view.k + view.y ];
+    }
+    function scaleTo(s) {
+      view.k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], s));
+    }
+    function translateTo(p, l) {
+      l = point(l);
+      view.x += p[0] - l[0];
+      view.y += p[1] - l[1];
+    }
+    function rescale() {
+      if (x1) x1.domain(x0.range().map(function(x) {
+        return (x - view.x) / view.k;
+      }).map(x0.invert));
+      if (y1) y1.domain(y0.range().map(function(y) {
+        return (y - view.y) / view.k;
+      }).map(y0.invert));
+    }
+    function zoomstarted(dispatch) {
+      dispatch({
+        type: "zoomstart"
+      });
+    }
+    function zoomed(dispatch) {
+      rescale();
+      dispatch({
+        type: "zoom",
+        scale: view.k,
+        translate: [ view.x, view.y ]
+      });
+    }
+    function zoomended(dispatch) {
+      dispatch({
+        type: "zoomend"
+      });
+    }
+    function mousedowned() {
+      var that = this, target = d3.event.target, dispatch = event.of(that, arguments), dragged = 0, subject = d3.select(d3_window).on(mousemove, moved).on(mouseup, ended), location0 = location(d3.mouse(that)), dragRestore = d3_event_dragSuppress();
+      d3_selection_interrupt.call(that);
+      zoomstarted(dispatch);
+      function moved() {
+        dragged = 1;
+        translateTo(d3.mouse(that), location0);
+        zoomed(dispatch);
+      }
+      function ended() {
+        subject.on(mousemove, d3_window === that ? mousewheelreset : null).on(mouseup, null);
+        dragRestore(dragged && d3.event.target === target);
+        zoomended(dispatch);
+      }
+    }
+    function touchstarted() {
+      var that = this, dispatch = event.of(that, arguments), locations0 = {}, distance0 = 0, scale0, zoomName = ".zoom-" + d3.event.changedTouches[0].identifier, touchmove = "touchmove" + zoomName, touchend = "touchend" + zoomName, target = d3.select(d3.event.target).on(touchmove, moved).on(touchend, ended), subject = d3.select(that).on(mousedown, null).on(touchstart, started), dragRestore = d3_event_dragSuppress();
+      d3_selection_interrupt.call(that);
+      started();
+      zoomstarted(dispatch);
+      function relocate() {
+        var touches = d3.touches(that);
+        scale0 = view.k;
+        touches.forEach(function(t) {
+          if (t.identifier in locations0) locations0[t.identifier] = location(t);
+        });
+        return touches;
+      }
+      function started() {
+        var changed = d3.event.changedTouches;
+        for (var i = 0, n = changed.length; i < n; ++i) {
+          locations0[changed[i].identifier] = null;
+        }
+        var touches = relocate(), now = Date.now();
+        if (touches.length === 1) {
+          if (now - touchtime < 500) {
+            var p = touches[0], l = locations0[p.identifier];
+            scaleTo(view.k * 2);
+            translateTo(p, l);
+            d3_eventPreventDefault();
+            zoomed(dispatch);
+          }
+          touchtime = now;
+        } else if (touches.length > 1) {
+          var p = touches[0], q = touches[1], dx = p[0] - q[0], dy = p[1] - q[1];
+          distance0 = dx * dx + dy * dy;
+        }
+      }
+      function moved() {
+        var touches = d3.touches(that), p0, l0, p1, l1;
+        for (var i = 0, n = touches.length; i < n; ++i, l1 = null) {
+          p1 = touches[i];
+          if (l1 = locations0[p1.identifier]) {
+            if (l0) break;
+            p0 = p1, l0 = l1;
+          }
+        }
+        if (l1) {
+          var distance1 = (distance1 = p1[0] - p0[0]) * distance1 + (distance1 = p1[1] - p0[1]) * distance1, scale1 = distance0 && Math.sqrt(distance1 / distance0);
+          p0 = [ (p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2 ];
+          l0 = [ (l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2 ];
+          scaleTo(scale1 * scale0);
+        }
+        touchtime = null;
+        translateTo(p0, l0);
+        zoomed(dispatch);
+      }
+      function ended() {
+        if (d3.event.touches.length) {
+          var changed = d3.event.changedTouches;
+          for (var i = 0, n = changed.length; i < n; ++i) {
+            delete locations0[changed[i].identifier];
+          }
+          for (var identifier in locations0) {
+            return void relocate();
+          }
+        }
+        target.on(zoomName, null);
+        subject.on(mousedown, mousedowned).on(touchstart, touchstarted);
+        dragRestore();
+        zoomended(dispatch);
+      }
+    }
+    function mousewheeled() {
+      var dispatch = event.of(this, arguments);
+      if (mousewheelTimer) clearTimeout(mousewheelTimer); else d3_selection_interrupt.call(this), 
+      zoomstarted(dispatch);
+      mousewheelTimer = setTimeout(function() {
+        mousewheelTimer = null;
+        zoomended(dispatch);
+      }, 50);
+      d3_eventPreventDefault();
+      var point = center || d3.mouse(this);
+      if (!translate0) translate0 = location(point);
+      scaleTo(Math.pow(2, d3_behavior_zoomDelta() * .002) * view.k);
+      translateTo(point, translate0);
+      zoomed(dispatch);
+    }
+    function mousewheelreset() {
+      translate0 = null;
+    }
+    function dblclicked() {
+      var dispatch = event.of(this, arguments), p = d3.mouse(this), l = location(p), k = Math.log(view.k) / Math.LN2;
+      zoomstarted(dispatch);
+      scaleTo(Math.pow(2, d3.event.shiftKey ? Math.ceil(k) - 1 : Math.floor(k) + 1));
+      translateTo(p, l);
+      zoomed(dispatch);
+      zoomended(dispatch);
+    }
+    return d3.rebind(zoom, event, "on");
+  };
+  var d3_behavior_zoomInfinity = [ 0, Infinity ];
+  var d3_behavior_zoomDelta, d3_behavior_zoomWheel = "onwheel" in d3_document ? (d3_behavior_zoomDelta = function() {
+    return -d3.event.deltaY * (d3.event.deltaMode ? 120 : 1);
+  }, "wheel") : "onmousewheel" in d3_document ? (d3_behavior_zoomDelta = function() {
+    return d3.event.wheelDelta;
+  }, "mousewheel") : (d3_behavior_zoomDelta = function() {
+    return -d3.event.detail;
+  }, "MozMousePixelScroll");
+  function d3_Color() {}
+  d3_Color.prototype.toString = function() {
+    return this.rgb() + "";
+  };
+  d3.hsl = function(h, s, l) {
+    return arguments.length === 1 ? h instanceof d3_Hsl ? d3_hsl(h.h, h.s, h.l) : d3_rgb_parse("" + h, d3_rgb_hsl, d3_hsl) : d3_hsl(+h, +s, +l);
+  };
+  function d3_hsl(h, s, l) {
+    return new d3_Hsl(h, s, l);
+  }
+  function d3_Hsl(h, s, l) {
+    this.h = h;
+    this.s = s;
+    this.l = l;
+  }
+  var d3_hslPrototype = d3_Hsl.prototype = new d3_Color();
+  d3_hslPrototype.brighter = function(k) {
+    k = Math.pow(.7, arguments.length ? k : 1);
+    return d3_hsl(this.h, this.s, this.l / k);
+  };
+  d3_hslPrototype.darker = function(k) {
+    k = Math.pow(.7, arguments.length ? k : 1);
+    return d3_hsl(this.h, this.s, k * this.l);
+  };
+  d3_hslPrototype.rgb = function() {
+    return d3_hsl_rgb(this.h, this.s, this.l);
+  };
+  function d3_hsl_rgb(h, s, l) {
+    var m1, m2;
+    h = isNaN(h) ? 0 : (h %= 360) < 0 ? h + 360 : h;
+    s = isNaN(s) ? 0 : s < 0 ? 0 : s > 1 ? 1 : s;
+    l = l < 0 ? 0 : l > 1 ? 1 : l;
+    m2 = l <= .5 ? l * (1 + s) : l + s - l * s;
+    m1 = 2 * l - m2;
+    function v(h) {
+      if (h > 360) h -= 360; else if (h < 0) h += 360;
+      if (h < 60) return m1 + (m2 - m1) * h / 60;
+      if (h < 180) return m2;
+      if (h < 240) return m1 + (m2 - m1) * (240 - h) / 60;
+      return m1;
+    }
+    function vv(h) {
+      return Math.round(v(h) * 255);
+    }
+    return d3_rgb(vv(h + 120), vv(h), vv(h - 120));
+  }
+  d3.hcl = function(h, c, l) {
+    return arguments.length === 1 ? h instanceof d3_Hcl ? d3_hcl(h.h, h.c, h.l) : h instanceof d3_Lab ? d3_lab_hcl(h.l, h.a, h.b) : d3_lab_hcl((h = d3_rgb_lab((h = d3.rgb(h)).r, h.g, h.b)).l, h.a, h.b) : d3_hcl(+h, +c, +l);
+  };
+  function d3_hcl(h, c, l) {
+    return new d3_Hcl(h, c, l);
+  }
+  function d3_Hcl(h, c, l) {
+    this.h = h;
+    this.c = c;
+    this.l = l;
+  }
+  var d3_hclPrototype = d3_Hcl.prototype = new d3_Color();
+  d3_hclPrototype.brighter = function(k) {
+    return d3_hcl(this.h, this.c, Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)));
+  };
+  d3_hclPrototype.darker = function(k) {
+    return d3_hcl(this.h, this.c, Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)));
+  };
+  d3_hclPrototype.rgb = function() {
+    return d3_hcl_lab(this.h, this.c, this.l).rgb();
+  };
+  function d3_hcl_lab(h, c, l) {
+    if (isNaN(h)) h = 0;
+    if (isNaN(c)) c = 0;
+    return d3_lab(l, Math.cos(h *= d3_radians) * c, Math.sin(h) * c);
+  }
+  d3.lab = function(l, a, b) {
+    return arguments.length === 1 ? l instanceof d3_Lab ? d3_lab(l.l, l.a, l.b) : l instanceof d3_Hcl ? d3_hcl_lab(l.l, l.c, l.h) : d3_rgb_lab((l = d3.rgb(l)).r, l.g, l.b) : d3_lab(+l, +a, +b);
+  };
+  function d3_lab(l, a, b) {
+    return new d3_Lab(l, a, b);
+  }
+  function d3_Lab(l, a, b) {
+    this.l = l;
+    this.a = a;
+    this.b = b;
+  }
+  var d3_lab_K = 18;
+  var d3_lab_X = .95047, d3_lab_Y = 1, d3_lab_Z = 1.08883;
+  var d3_labPrototype = d3_Lab.prototype = new d3_Color();
+  d3_labPrototype.brighter = function(k) {
+    return d3_lab(Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)), this.a, this.b);
+  };
+  d3_labPrototype.darker = function(k) {
+    return d3_lab(Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)), this.a, this.b);
+  };
+  d3_labPrototype.rgb = function() {
+    return d3_lab_rgb(this.l, this.a, this.b);
+  };
+  function d3_lab_rgb(l, a, b) {
+    var y = (l + 16) / 116, x = y + a / 500, z = y - b / 200;
+    x = d3_lab_xyz(x) * d3_lab_X;
+    y = d3_lab_xyz(y) * d3_lab_Y;
+    z = d3_lab_xyz(z) * d3_lab_Z;
+    return d3_rgb(d3_xyz_rgb(3.2404542 * x - 1.5371385 * y - .4985314 * z), d3_xyz_rgb(-.969266 * x + 1.8760108 * y + .041556 * z), d3_xyz_rgb(.0556434 * x - .2040259 * y + 1.0572252 * z));
+  }
+  function d3_lab_hcl(l, a, b) {
+    return l > 0 ? d3_hcl(Math.atan2(b, a) * d3_degrees, Math.sqrt(a * a + b * b), l) : d3_hcl(NaN, NaN, l);
+  }
+  function d3_lab_xyz(x) {
+    return x > .206893034 ? x * x * x : (x - 4 / 29) / 7.787037;
+  }
+  function d3_xyz_lab(x) {
+    return x > .008856 ? Math.pow(x, 1 / 3) : 7.787037 * x + 4 / 29;
+  }
+  function d3_xyz_rgb(r) {
+    return Math.round(255 * (r <= .00304 ? 12.92 * r : 1.055 * Math.pow(r, 1 / 2.4) - .055));
+  }
+  d3.rgb = function(r, g, b) {
+    return arguments.length === 1 ? r instanceof d3_Rgb ? d3_rgb(r.r, r.g, r.b) : d3_rgb_parse("" + r, d3_rgb, d3_hsl_rgb) : d3_rgb(~~r, ~~g, ~~b);
+  };
+  function d3_rgbNumber(value) {
+    return d3_rgb(value >> 16, value >> 8 & 255, value & 255);
+  }
+  function d3_rgbString(value) {
+    return d3_rgbNumber(value) + "";
+  }
+  function d3_rgb(r, g, b) {
+    return new d3_Rgb(r, g, b);
+  }
+  function d3_Rgb(r, g, b) {
+    this.r = r;
+    this.g = g;
+    this.b = b;
+  }
+  var d3_rgbPrototype = d3_Rgb.prototype = new d3_Color();
+  d3_rgbPrototype.brighter = function(k) {
+    k = Math.pow(.7, arguments.length ? k : 1);
+    var r = this.r, g = this.g, b = this.b, i = 30;
+    if (!r && !g && !b) return d3_rgb(i, i, i);
+    if (r && r < i) r = i;
+    if (g && g < i) g = i;
+    if (b && b < i) b = i;
+    return d3_rgb(Math.min(255, ~~(r / k)), Math.min(255, ~~(g / k)), Math.min(255, ~~(b / k)));
+  };
+  d3_rgbPrototype.darker = function(k) {
+    k = Math.pow(.7, arguments.length ? k : 1);
+    return d3_rgb(~~(k * this.r), ~~(k * this.g), ~~(k * this.b));
+  };
+  d3_rgbPrototype.hsl = function() {
+    return d3_rgb_hsl(this.r, this.g, this.b);
+  };
+  d3_rgbPrototype.toString = function() {
+    return "#" + d3_rgb_hex(this.r) + d3_rgb_hex(this.g) + d3_rgb_hex(this.b);
+  };
+  function d3_rgb_hex(v) {
+    return v < 16 ? "0" + Math.max(0, v).toString(16) : Math.min(255, v).toString(16);
+  }
+  function d3_rgb_parse(format, rgb, hsl) {
+    var r = 0, g = 0, b = 0, m1, m2, color;
+    m1 = /([a-z]+)\((.*)\)/i.exec(format);
+    if (m1) {
+      m2 = m1[2].split(",");
+      switch (m1[1]) {
+       case "hsl":
+        {
+          return hsl(parseFloat(m2[0]), parseFloat(m2[1]) / 100, parseFloat(m2[2]) / 100);
+        }
+
+       case "rgb":
+        {
+          return rgb(d3_rgb_parseNumber(m2[0]), d3_rgb_parseNumber(m2[1]), d3_rgb_parseNumber(m2[2]));
+        }
+      }
+    }
+    if (color = d3_rgb_names.get(format)) return rgb(color.r, color.g, color.b);
+    if (format != null && format.charAt(0) === "#" && !isNaN(color = parseInt(format.substring(1), 16))) {
+      if (format.length === 4) {
+        r = (color & 3840) >> 4;
+        r = r >> 4 | r;
+        g = color & 240;
+        g = g >> 4 | g;
+        b = color & 15;
+        b = b << 4 | b;
+      } else if (format.length === 7) {
+        r = (color & 16711680) >> 16;
+        g = (color & 65280) >> 8;
+        b = color & 255;
+      }
+    }
+    return rgb(r, g, b);
+  }
+  function d3_rgb_hsl(r, g, b) {
+    var min = Math.min(r /= 255, g /= 255, b /= 255), max = Math.max(r, g, b), d = max - min, h, s, l = (max + min) / 2;
+    if (d) {
+      s = l < .5 ? d / (max + min) : d / (2 - max - min);
+      if (r == max) h = (g - b) / d + (g < b ? 6 : 0); else if (g == max) h = (b - r) / d + 2; else h = (r - g) / d + 4;
+      h *= 60;
+    } else {
+      h = NaN;
+      s = l > 0 && l < 1 ? 0 : h;
+    }
+    return d3_hsl(h, s, l);
+  }
+  function d3_rgb_lab(r, g, b) {
+    r = d3_rgb_xyz(r);
+    g = d3_rgb_xyz(g);
+    b = d3_rgb_xyz(b);
+    var x = d3_xyz_lab((.4124564 * r + .3575761 * g + .1804375 * b) / d3_lab_X), y = d3_xyz_lab((.2126729 * r + .7151522 * g + .072175 * b) / d3_lab_Y), z = d3_xyz_lab((.0193339 * r + .119192 * g + .9503041 * b) / d3_lab_Z);
+    return d3_lab(116 * y - 16, 500 * (x - y), 200 * (y - z));
+  }
+  function d3_rgb_xyz(r) {
+    return (r /= 255) <= .04045 ? r / 12.92 : Math.pow((r + .055) / 1.055, 2.4);
+  }
+  function d3_rgb_parseNumber(c) {
+    var f = parseFloat(c);
+    return c.charAt(c.length - 1) === "%" ? Math.round(f * 2.55) : f;
+  }
+  var d3_rgb_names = d3.map({
+    aliceblue: 15792383,
+    antiquewhite: 16444375,
+    aqua: 65535,
+    aquamarine: 8388564,
+    azure: 15794175,
+    beige: 16119260,
+    bisque: 16770244,
+    black: 0,
+    blanchedalmond: 16772045,
+    blue: 255,
+    blueviolet: 9055202,
+    brown: 10824234,
+    burlywood: 14596231,
+    cadetblue: 6266528,
+    chartreuse: 8388352,
+    chocolate: 13789470,
+    coral: 16744272,
+    cornflowerblue: 6591981,
+    cornsilk: 16775388,
+    crimson: 14423100,
+    cyan: 65535,
+    darkblue: 139,
+    darkcyan: 35723,
+    darkgoldenrod: 12092939,
+    darkgray: 11119017,
+    darkgreen: 25600,
+    darkgrey: 11119017,
+    darkkhaki: 12433259,
+    darkmagenta: 9109643,
+    darkolivegreen: 5597999,
+    darkorange: 16747520,
+    darkorchid: 10040012,
+    darkred: 9109504,
+    darksalmon: 15308410,
+    darkseagreen: 9419919,
+    darkslateblue: 4734347,
+    darkslategray: 3100495,
+    darkslategrey: 3100495,
+    darkturquoise: 52945,
+    darkviolet: 9699539,
+    deeppink: 16716947,
+    deepskyblue: 49151,
+    dimgray: 6908265,
+    dimgrey: 6908265,
+    dodgerblue: 2003199,
+    firebrick: 11674146,
+    floralwhite: 16775920,
+    forestgreen: 2263842,
+    fuchsia: 16711935,
+    gainsboro: 14474460,
+    ghostwhite: 16316671,
+    gold: 16766720,
+    goldenrod: 14329120,
+    gray: 8421504,
+    green: 32768,
+    greenyellow: 11403055,
+    grey: 8421504,
+    honeydew: 15794160,
+    hotpink: 16738740,
+    indianred: 13458524,
+    indigo: 4915330,
+    ivory: 16777200,
+    khaki: 15787660,
+    lavender: 15132410,
+    lavenderblush: 16773365,
+    lawngreen: 8190976,
+    lemonchiffon: 16775885,
+    lightblue: 11393254,
+    lightcoral: 15761536,
+    lightcyan: 14745599,
+    lightgoldenrodyellow: 16448210,
+    lightgray: 13882323,
+    lightgreen: 9498256,
+    lightgrey: 13882323,
+    lightpink: 16758465,
+    lightsalmon: 16752762,
+    lightseagreen: 2142890,
+    lightskyblue: 8900346,
+    lightslategray: 7833753,
+    lightslategrey: 7833753,
+    lightsteelblue: 11584734,
+    lightyellow: 16777184,
+    lime: 65280,
+    limegreen: 3329330,
+    linen: 16445670,
+    magenta: 16711935,
+    maroon: 8388608,
+    mediumaquamarine: 6737322,
+    mediumblue: 205,
+    mediumorchid: 12211667,
+    mediumpurple: 9662683,
+    mediumseagreen: 3978097,
+    mediumslateblue: 8087790,
+    mediumspringgreen: 64154,
+    mediumturquoise: 4772300,
+    mediumvioletred: 13047173,
+    midnightblue: 1644912,
+    mintcream: 16121850,
+    mistyrose: 16770273,
+    moccasin: 16770229,
+    navajowhite: 16768685,
+    navy: 128,
+    oldlace: 16643558,
+    olive: 8421376,
+    olivedrab: 7048739,
+    orange: 16753920,
+    orangered: 16729344,
+    orchid: 14315734,
+    palegoldenrod: 15657130,
+    palegreen: 10025880,
+    paleturquoise: 11529966,
+    palevioletred: 14381203,
+    papayawhip: 16773077,
+    peachpuff: 16767673,
+    peru: 13468991,
+    pink: 16761035,
+    plum: 14524637,
+    powderblue: 11591910,
+    purple: 8388736,
+    red: 16711680,
+    rosybrown: 12357519,
+    royalblue: 4286945,
+    saddlebrown: 9127187,
+    salmon: 16416882,
+    sandybrown: 16032864,
+    seagreen: 3050327,
+    seashell: 16774638,
+    sienna: 10506797,
+    silver: 12632256,
+    skyblue: 8900331,
+    slateblue: 6970061,
+    slategray: 7372944,
+    slategrey: 7372944,
+    snow: 16775930,
+    springgreen: 65407,
+    steelblue: 4620980,
+    tan: 13808780,
+    teal: 32896,
+    thistle: 14204888,
+    tomato: 16737095,
+    turquoise: 4251856,
+    violet: 15631086,
+    wheat: 16113331,
+    white: 16777215,
+    whitesmoke: 16119285,
+    yellow: 16776960,
+    yellowgreen: 10145074
+  });
+  d3_rgb_names.forEach(function(key, value) {
+    d3_rgb_names.set(key, d3_rgbNumber(value));
+  });
+  function d3_functor(v) {
+    return typeof v === "function" ? v : function() {
+      return v;
+    };
+  }
+  d3.functor = d3_functor;
+  function d3_identity(d) {
+    return d;
+  }
+  d3.xhr = d3_xhrType(d3_identity);
+  function d3_xhrType(response) {
+    return function(url, mimeType, callback) {
+      if (arguments.length === 2 && typeof mimeType === "function") callback = mimeType, 
+      mimeType = null;
+      return d3_xhr(url, mimeType, response, callback);
+    };
+  }
+  function d3_xhr(url, mimeType, response, callback) {
+    var xhr = {}, dispatch = d3.dispatch("beforesend", "progress", "load", "error"), headers = {}, request = new XMLHttpRequest(), responseType = null;
+    if (d3_window.XDomainRequest && !("withCredentials" in request) && /^(http(s)?:)?\/\//.test(url)) request = new XDomainRequest();
+    "onload" in request ? request.onload = request.onerror = respond : request.onreadystatechange = function() {
+      request.readyState > 3 && respond();
+    };
+    function respond() {
+      var status = request.status, result;
+      if (!status && request.responseText || status >= 200 && status < 300 || status === 304) {
+        try {
+          result = response.call(xhr, request);
+        } catch (e) {
+          dispatch.error.call(xhr, e);
+          return;
+        }
+        dispatch.load.call(xhr, result);
+      } else {
+        dispatch.error.call(xhr, request);
+      }
+    }
+    request.onprogress = function(event) {
+      var o = d3.event;
+      d3.event = event;
+      try {
+        dispatch.progress.call(xhr, request);
+      } finally {
+        d3.event = o;
+      }
+    };
+    xhr.header = function(name, value) {
+      name = (name + "").toLowerCase();
+      if (arguments.length < 2) return headers[name];
+      if (value == null) delete headers[name]; else headers[name] = value + "";
+      return xhr;
+    };
+    xhr.mimeType = function(value) {
+      if (!arguments.length) return mimeType;
+      mimeType = value == null ? null : value + "";
+      return xhr;
+    };
+    xhr.responseType = function(value) {
+      if (!arguments.length) return responseType;
+      responseType = value;
+      return xhr;
+    };
+    xhr.response = function(value) {
+      response = value;
+      return xhr;
+    };
+    [ "get", "post" ].forEach(function(method) {
+      xhr[method] = function() {
+        return xhr.send.apply(xhr, [ method ].concat(d3_array(arguments)));
+      };
+    });
+    xhr.send = function(method, data, callback) {
+      if (arguments.length === 2 && typeof data === "function") callback = data, data = null;
+      request.open(method, url, true);
+      if (mimeType != null && !("accept" in headers)) headers["accept"] = mimeType + ",*/*";
+      if (request.setRequestHeader) for (var name in headers) request.setRequestHeader(name, headers[name]);
+      if (mimeType != null && request.overrideMimeType) request.overrideMimeType(mimeType);
+      if (responseType != null) request.responseType = responseType;
+      if (callback != null) xhr.on("error", callback).on("load", function(request) {
+        callback(null, request);
+      });
+      dispatch.beforesend.call(xhr, request);
+      request.send(data == null ? null : data);
+      return xhr;
+    };
+    xhr.abort = function() {
+      request.abort();
+      return xhr;
+    };
+    d3.rebind(xhr, dispatch, "on");
+    return callback == null ? xhr : xhr.get(d3_xhr_fixCallback(callback));
+  }
+  function d3_xhr_fixCallback(callback) {
+    return callback.length === 1 ? function(error, request) {
+      callback(error == null ? request : null);
+    } : callback;
+  }
+  d3.dsv = function(delimiter, mimeType) {
+    var reFormat = new RegExp('["' + delimiter + "\n]"), delimiterCode = delimiter.charCodeAt(0);
+    function dsv(url, row, callback) {
+      if (arguments.length < 3) callback = row, row = null;
+      var xhr = d3_xhr(url, mimeType, row == null ? response : typedResponse(row), callback);
+      xhr.row = function(_) {
+        return arguments.length ? xhr.response((row = _) == null ? response : typedResponse(_)) : row;
+      };
+      return xhr;
+    }
+    function response(request) {
+      return dsv.parse(request.responseText);
+    }
+    function typedResponse(f) {
+      return function(request) {
+        return dsv.parse(request.responseText, f);
+      };
+    }
+    dsv.parse = function(text, f) {
+      var o;
+      return dsv.parseRows(text, function(row, i) {
+        if (o) return o(row, i - 1);
+        var a = new Function("d", "return {" + row.map(function(name, i) {
+          return JSON.stringify(name) + ": d[" + i + "]";
+        }).join(",") + "}");
+        o = f ? function(row, i) {
+          return f(a(row), i);
+        } : a;
+      });
+    };
+    dsv.parseRows = function(text, f) {
+      var EOL = {}, EOF = {}, rows = [], N = text.length, I = 0, n = 0, t, eol;
+      function token() {
+        if (I >= N) return EOF;
+        if (eol) return eol = false, EOL;
+        var j = I;
+        if (text.charCodeAt(j) === 34) {
+          var i = j;
+          while (i++ < N) {
+            if (text.charCodeAt(i) === 34) {
+              if (text.charCodeAt(i + 1) !== 34) break;
+              ++i;
+            }
+          }
+          I = i + 2;
+          var c = text.charCodeAt(i + 1);
+          if (c === 13) {
+            eol = true;
+            if (text.charCodeAt(i + 2) === 10) ++I;
+          } else if (c === 10) {
+            eol = true;
+          }
+          return text.substring(j + 1, i).replace(/""/g, '"');
+        }
+        while (I < N) {
+          var c = text.charCodeAt(I++), k = 1;
+          if (c === 10) eol = true; else if (c === 13) {
+            eol = true;
+            if (text.charCodeAt(I) === 10) ++I, ++k;
+          } else if (c !== delimiterCode) continue;
+          return text.substring(j, I - k);
+        }
+        return text.substring(j);
+      }
+      while ((t = token()) !== EOF) {
+        var a = [];
+        while (t !== EOL && t !== EOF) {
+          a.push(t);
+          t = token();
+        }
+        if (f && !(a = f(a, n++))) continue;
+        rows.push(a);
+      }
+      return rows;
+    };
+    dsv.format = function(rows) {
+      if (Array.isArray(rows[0])) return dsv.formatRows(rows);
+      var fieldSet = new d3_Set(), fields = [];
+      rows.forEach(function(row) {
+        for (var field in row) {
+          if (!fieldSet.has(field)) {
+            fields.push(fieldSet.add(field));
+          }
+        }
+      });
+      return [ fields.map(formatValue).join(delimiter) ].concat(rows.map(function(row) {
+        return fields.map(function(field) {
+          return formatValue(row[field]);
+        }).join(delimiter);
+      })).join("\n");
+    };
+    dsv.formatRows = function(rows) {
+      return rows.map(formatRow).join("\n");
+    };
+    function formatRow(row) {
+      return row.map(formatValue).join(delimiter);
+    }
+    function formatValue(text) {
+      return reFormat.test(text) ? '"' + text.replace(/\"/g, '""') + '"' : text;
+    }
+    return dsv;
+  };
+  d3.csv = d3.dsv(",", "text/csv");
+  d3.tsv = d3.dsv("	", "text/tab-separated-values");
+  d3.touch = function(container, touches, identifier) {
+    if (arguments.length < 3) identifier = touches, touches = d3_eventSource().changedTouches;
+    if (touches) for (var i = 0, n = touches.length, touch; i < n; ++i) {
+      if ((touch = touches[i]).identifier === identifier) {
+        return d3_mousePoint(container, touch);
+      }
+    }
+  };
+  var d3_timer_queueHead, d3_timer_queueTail, d3_timer_interval, d3_timer_timeout, d3_timer_active, d3_timer_frame = d3_window[d3_vendorSymbol(d3_window, "requestAnimationFrame")] || function(callback) {
+    setTimeout(callback, 17);
+  };
+  d3.timer = function(callback, delay, then) {
+    var n = arguments.length;
+    if (n < 2) delay = 0;
+    if (n < 3) then = Date.now();
+    var time = then + delay, timer = {
+      c: callback,
+      t: time,
+      f: false,
+      n: null
+    };
+    if (d3_timer_queueTail) d3_timer_queueTail.n = timer; else d3_timer_queueHead = timer;
+    d3_timer_queueTail = timer;
+    if (!d3_timer_interval) {
+      d3_timer_timeout = clearTimeout(d3_timer_timeout);
+      d3_timer_interval = 1;
+      d3_timer_frame(d3_timer_step);
+    }
+  };
+  function d3_timer_step() {
+    var now = d3_timer_mark(), delay = d3_timer_sweep() - now;
+    if (delay > 24) {
+      if (isFinite(delay)) {
+        clearTimeout(d3_timer_timeout);
+        d3_timer_timeout = setTimeout(d3_timer_step, delay);
+      }
+      d3_timer_interval = 0;
+    } else {
+      d3_timer_interval = 1;
+      d3_timer_frame(d3_timer_step);
+    }
+  }
+  d3.timer.flush = function() {
+    d3_timer_mark();
+    d3_timer_sweep();
+  };
+  function d3_timer_mark() {
+    var now = Date.now();
+    d3_timer_active = d3_timer_queueHead;
+    while (d3_timer_active) {
+      if (now >= d3_timer_active.t) d3_timer_active.f = d3_timer_active.c(now - d3_timer_active.t);
+      d3_timer_active = d3_timer_active.n;
+    }
+    return now;
+  }
+  function d3_timer_sweep() {
+    var t0, t1 = d3_timer_queueHead, time = Infinity;
+    while (t1) {
+      if (t1.f) {
+        t1 = t0 ? t0.n = t1.n : d3_timer_queueHead = t1.n;
+      } else {
+        if (t1.t < time) time = t1.t;
+        t1 = (t0 = t1).n;
+      }
+    }
+    d3_timer_queueTail = t0;
+    return time;
+  }
+  function d3_format_precision(x, p) {
+    return p - (x ? Math.ceil(Math.log(x) / Math.LN10) : 1);
+  }
+  d3.round = function(x, n) {
+    return n ? Math.round(x * (n = Math.pow(10, n))) / n : Math.round(x);
+  };
+  var d3_formatPrefixes = [ "y", "z", "a", "f", "p", "n", "µ", "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y" ].map(d3_formatPrefix);
+  d3.formatPrefix = function(value, precision) {
+    var i = 0;
+    if (value) {
+      if (value < 0) value *= -1;
+      if (precision) value = d3.round(value, d3_format_precision(value, precision));
+      i = 1 + Math.floor(1e-12 + Math.log(value) / Math.LN10);
+      i = Math.max(-24, Math.min(24, Math.floor((i - 1) / 3) * 3));
+    }
+    return d3_formatPrefixes[8 + i / 3];
+  };
+  function d3_formatPrefix(d, i) {
+    var k = Math.pow(10, abs(8 - i) * 3);
+    return {
+      scale: i > 8 ? function(d) {
+        return d / k;
+      } : function(d) {
+        return d * k;
+      },
+      symbol: d
+    };
+  }
+  function d3_locale_numberFormat(locale) {
+    var locale_decimal = locale.decimal, locale_thousands = locale.thousands, locale_grouping = locale.grouping, locale_currency = locale.currency, formatGroup = locale_grouping ? function(value) {
+      var i = value.length, t = [], j = 0, g = locale_grouping[0];
+      while (i > 0 && g > 0) {
+        t.push(value.substring(i -= g, i + g));
+        g = locale_grouping[j = (j + 1) % locale_grouping.length];
+      }
+      return t.reverse().join(locale_thousands);
+    } : d3_identity;
+    return function(specifier) {
+      var match = d3_format_re.exec(specifier), fill = match[1] || " ", align = match[2] || ">", sign = match[3] || "", symbol = match[4] || "", zfill = match[5], width = +match[6], comma = match[7], precision = match[8], type = match[9], scale = 1, prefix = "", suffix = "", integer = false;
+      if (precision) precision = +precision.substring(1);
+      if (zfill || fill === "0" && align === "=") {
+        zfill = fill = "0";
+        align = "=";
+        if (comma) width -= Math.floor((width - 1) / 4);
+      }
+      switch (type) {
+       case "n":
+        comma = true;
+        type = "g";
+        break;
+
+       case "%":
+        scale = 100;
+        suffix = "%";
+        type = "f";
+        break;
+
+       case "p":
+        scale = 100;
+        suffix = "%";
+        type = "r";
+        break;
+
+       case "b":
+       case "o":
+       case "x":
+       case "X":
+        if (symbol === "#") prefix = "0" + type.toLowerCase();
+
+       case "c":
+       case "d":
+        integer = true;
+        precision = 0;
+        break;
+
+       case "s":
+        scale = -1;
+        type = "r";
+        break;
+      }
+      if (symbol === "$") prefix = locale_currency[0], suffix = locale_currency[1];
+      if (type == "r" && !precision) type = "g";
+      if (precision != null) {
+        if (type == "g") precision = Math.max(1, Math.min(21, precision)); else if (type == "e" || type == "f") precision = Math.max(0, Math.min(20, precision));
+      }
+      type = d3_format_types.get(type) || d3_format_typeDefault;
+      var zcomma = zfill && comma;
+      return function(value) {
+        var fullSuffix = suffix;
+        if (integer && value % 1) return "";
+        var negative = value < 0 || value === 0 && 1 / value < 0 ? (value = -value, "-") : sign;
+        if (scale < 0) {
+          var unit = d3.formatPrefix(value, precision);
+          value = unit.scale(value);
+          fullSuffix = unit.symbol + suffix;
+        } else {
+          value *= scale;
+        }
+        value = type(value, precision);
+        var i = value.lastIndexOf("."), before = i < 0 ? value : value.substring(0, i), after = i < 0 ? "" : locale_decimal + value.substring(i + 1);
+        if (!zfill && comma) before = formatGroup(before);
+        var length = prefix.length + before.length + after.length + (zcomma ? 0 : negative.length), padding = length < width ? new Array(length = width - length + 1).join(fill) : "";
+        if (zcomma) before = formatGroup(padding + before);
+        negative += prefix;
+        value = before + after;
+        return (align === "<" ? negative + value + padding : align === ">" ? padding + negative + value : align === "^" ? padding.substring(0, length >>= 1) + negative + value + padding.substring(length) : negative + (zcomma ? value : padding + value)) + fullSuffix;
+      };
+    };
+  }
+  var d3_format_re = /(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i;
+  var d3_format_types = d3.map({
+    b: function(x) {
+      return x.toString(2);
+    },
+    c: function(x) {
+      return String.fromCharCode(x);
+    },
+    o: function(x) {
+      return x.toString(8);
+    },
+    x: function(x) {
+      return x.toString(16);
+    },
+    X: function(x) {
+      return x.toString(16).toUpperCase();
+    },
+    g: function(x, p) {
+      return x.toPrecision(p);
+    },
+    e: function(x, p) {
+      return x.toExponential(p);
+    },
+    f: function(x, p) {
+      return x.toFixed(p);
+    },
+    r: function(x, p) {
+      return (x = d3.round(x, d3_format_precision(x, p))).toFixed(Math.max(0, Math.min(20, d3_format_precision(x * (1 + 1e-15), p))));
+    }
+  });
+  function d3_format_typeDefault(x) {
+    return x + "";
+  }
+  var d3_time = d3.time = {}, d3_date = Date;
+  function d3_date_utc() {
+    this._ = new Date(arguments.length > 1 ? Date.UTC.apply(this, arguments) : arguments[0]);
+  }
+  d3_date_utc.prototype = {
+    getDate: function() {
+      return this._.getUTCDate();
+    },
+    getDay: function() {
+      return this._.getUTCDay();
+    },
+    getFullYear: function() {
+      return this._.getUTCFullYear();
+    },
+    getHours: function() {
+      return this._.getUTCHours();
+    },
+    getMilliseconds: function() {
+      return this._.getUTCMilliseconds();
+    },
+    getMinutes: function() {
+      return this._.getUTCMinutes();
+    },
+    getMonth: function() {
+      return this._.getUTCMonth();
+    },
+    getSeconds: function() {
+      return this._.getUTCSeconds();
+    },
+    getTime: function() {
+      return this._.getTime();
+    },
+    getTimezoneOffset: function() {
+      return 0;
+    },
+    valueOf: function() {
+      return this._.valueOf();
+    },
+    setDate: function() {
+      d3_time_prototype.setUTCDate.apply(this._, arguments);
+    },
+    setDay: function() {
+      d3_time_prototype.setUTCDay.apply(this._, arguments);
+    },
+    setFullYear: function() {
+      d3_time_prototype.setUTCFullYear.apply(this._, arguments);
+    },
+    setHours: function() {
+      d3_time_prototype.setUTCHours.apply(this._, arguments);
+    },
+    setMilliseconds: function() {
+      d3_time_prototype.setUTCMilliseconds.apply(this._, arguments);
+    },
+    setMinutes: function() {
+      d3_time_prototype.setUTCMinutes.apply(this._, arguments);
+    },
+    setMonth: function() {
+      d3_time_prototype.setUTCMonth.apply(this._, arguments);
+    },
+    setSeconds: function() {
+      d3_time_prototype.setUTCSeconds.apply(this._, arguments);
+    },
+    setTime: function() {
+      d3_time_prototype.setTime.apply(this._, arguments);
+    }
+  };
+  var d3_time_prototype = Date.prototype;
+  function d3_time_interval(local, step, number) {
+    function round(date) {
+      var d0 = local(date), d1 = offset(d0, 1);
+      return date - d0 < d1 - date ? d0 : d1;
+    }
+    function ceil(date) {
+      step(date = local(new d3_date(date - 1)), 1);
+      return date;
+    }
+    function offset(date, k) {
+      step(date = new d3_date(+date), k);
+      return date;
+    }
+    function range(t0, t1, dt) {
+      var time = ceil(t0), times = [];
+      if (dt > 1) {
+        while (time < t1) {
+          if (!(number(time) % dt)) times.push(new Date(+time));
+          step(time, 1);
+        }
+      } else {
+        while (time < t1) times.push(new Date(+time)), step(time, 1);
+      }
+      return times;
+    }
+    function range_utc(t0, t1, dt) {
+      try {
+        d3_date = d3_date_utc;
+        var utc = new d3_date_utc();
+        utc._ = t0;
+        return range(utc, t1, dt);
+      } finally {
+        d3_date = Date;
+      }
+    }
+    local.floor = local;
+    local.round = round;
+    local.ceil = ceil;
+    local.offset = offset;
+    local.range = range;
+    var utc = local.utc = d3_time_interval_utc(local);
+    utc.floor = utc;
+    utc.round = d3_time_interval_utc(round);
+    utc.ceil = d3_time_interval_utc(ceil);
+    utc.offset = d3_time_interval_utc(offset);
+    utc.range = range_utc;
+    return local;
+  }
+  function d3_time_interval_utc(method) {
+    return function(date, k) {
+      try {
+        d3_date = d3_date_utc;
+        var utc = new d3_date_utc();
+        utc._ = date;
+        return method(utc, k)._;
+      } finally {
+        d3_date = Date;
+      }
+    };
+  }
+  d3_time.year = d3_time_interval(function(date) {
+    date = d3_time.day(date);
+    date.setMonth(0, 1);
+    return date;
+  }, function(date, offset) {
+    date.setFullYear(date.getFullYear() + offset);
+  }, function(date) {
+    return date.getFullYear();
+  });
+  d3_time.years = d3_time.year.range;
+  d3_time.years.utc = d3_time.year.utc.range;
+  d3_time.day = d3_time_interval(function(date) {
+    var day = new d3_date(2e3, 0);
+    day.setFullYear(date.getFullYear(), date.getMonth(), date.getDate());
+    return day;
+  }, function(date, offset) {
+    date.setDate(date.getDate() + offset);
+  }, function(date) {
+    return date.getDate() - 1;
+  });
+  d3_time.days = d3_time.day.range;
+  d3_time.days.utc = d3_time.day.utc.range;
+  d3_time.dayOfYear = function(date) {
+    var year = d3_time.year(date);
+    return Math.floor((date - year - (date.getTimezoneOffset() - year.getTimezoneOffset()) * 6e4) / 864e5);
+  };
+  [ "sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday" ].forEach(function(day, i) {
+    i = 7 - i;
+    var interval = d3_time[day] = d3_time_interval(function(date) {
+      (date = d3_time.day(date)).setDate(date.getDate() - (date.getDay() + i) % 7);
+      return date;
+    }, function(date, offset) {
+      date.setDate(date.getDate() + Math.floor(offset) * 7);
+    }, function(date) {
+      var day = d3_time.year(date).getDay();
+      return Math.floor((d3_time.dayOfYear(date) + (day + i) % 7) / 7) - (day !== i);
+    });
+    d3_time[day + "s"] = interval.range;
+    d3_time[day + "s"].utc = interval.utc.range;
+    d3_time[day + "OfYear"] = function(date) {
+      var day = d3_time.year(date).getDay();
+      return Math.floor((d3_time.dayOfYear(date) + (day + i) % 7) / 7);
+    };
+  });
+  d3_time.week = d3_time.sunday;
+  d3_time.weeks = d3_time.sunday.range;
+  d3_time.weeks.utc = d3_time.sunday.utc.range;
+  d3_time.weekOfYear = d3_time.sundayOfYear;
+  function d3_locale_timeFormat(locale) {
+    var locale_dateTime = locale.dateTime, locale_date = locale.date, locale_time = locale.time, locale_periods = locale.periods, locale_days = locale.days, locale_shortDays = locale.shortDays, locale_months = locale.months, locale_shortMonths = locale.shortMonths;
+    function d3_time_format(template) {
+      var n = template.length;
+      function format(date) {
+        var string = [], i = -1, j = 0, c, p, f;
+        while (++i < n) {
+          if (template.charCodeAt(i) === 37) {
+            string.push(template.substring(j, i));
+            if ((p = d3_time_formatPads[c = template.charAt(++i)]) != null) c = template.charAt(++i);
+            if (f = d3_time_formats[c]) c = f(date, p == null ? c === "e" ? " " : "0" : p);
+            string.push(c);
+            j = i + 1;
+          }
+        }
+        string.push(template.substring(j, i));
+        return string.join("");
+      }
+      format.parse = function(string) {
+        var d = {
+          y: 1900,
+          m: 0,
+          d: 1,
+          H: 0,
+          M: 0,
+          S: 0,
+          L: 0,
+          Z: null
+        }, i = d3_time_parse(d, template, string, 0);
+        if (i != string.length) return null;
+        if ("p" in d) d.H = d.H % 12 + d.p * 12;
+        var localZ = d.Z != null && d3_date !== d3_date_utc, date = new (localZ ? d3_date_utc : d3_date)();
+        if ("j" in d) date.setFullYear(d.y, 0, d.j); else if ("w" in d && ("W" in d || "U" in d)) {
+          date.setFullYear(d.y, 0, 1);
+          date.setFullYear(d.y, 0, "W" in d ? (d.w + 6) % 7 + d.W * 7 - (date.getDay() + 5) % 7 : d.w + d.U * 7 - (date.getDay() + 6) % 7);
+        } else date.setFullYear(d.y, d.m, d.d);
+        date.setHours(d.H + Math.floor(d.Z / 100), d.M + d.Z % 100, d.S, d.L);
+        return localZ ? date._ : date;
+      };
+      format.toString = function() {
+        return template;
+      };
+      return format;
+    }
+    function d3_time_parse(date, template, string, j) {
+      var c, p, t, i = 0, n = template.length, m = string.length;
+      while (i < n) {
+        if (j >= m) return -1;
+        c = template.charCodeAt(i++);
+        if (c === 37) {
+          t = template.charAt(i++);
+          p = d3_time_parsers[t in d3_time_formatPads ? template.charAt(i++) : t];
+          if (!p || (j = p(date, string, j)) < 0) return -1;
+        } else if (c != string.charCodeAt(j++)) {
+          return -1;
+        }
+      }
+      return j;
+    }
+    d3_time_format.utc = function(template) {
+      var local = d3_time_format(template);
+      function format(date) {
+        try {
+          d3_date = d3_date_utc;
+          var utc = new d3_date();
+          utc._ = date;
+          return local(utc);
+        } finally {
+          d3_date = Date;
+        }
+      }
+      format.parse = function(string) {
+        try {
+          d3_date = d3_date_utc;
+          var date = local.parse(string);
+          return date && date._;
+        } finally {
+          d3_date = Date;
+        }
+      };
+      format.toString = local.toString;
+      return format;
+    };
+    d3_time_format.multi = d3_time_format.utc.multi = d3_time_formatMulti;
+    var d3_time_periodLookup = d3.map(), d3_time_dayRe = d3_time_formatRe(locale_days), d3_time_dayLookup = d3_time_formatLookup(locale_days), d3_time_dayAbbrevRe = d3_time_formatRe(locale_shortDays), d3_time_dayAbbrevLookup = d3_time_formatLookup(locale_shortDays), d3_time_monthRe = d3_time_formatRe(locale_months), d3_time_monthLookup = d3_time_formatLookup(locale_months), d3_time_monthAbbrevRe = d3_time_formatRe(locale_shortMonths), d3_time_monthAbbrevLookup = d3_time_formatLookup(locale_shortMonths);
+    locale_periods.forEach(function(p, i) {
+      d3_time_periodLookup.set(p.toLowerCase(), i);
+    });
+    var d3_time_formats = {
+      a: function(d) {
+        return locale_shortDays[d.getDay()];
+      },
+      A: function(d) {
+        return locale_days[d.getDay()];
+      },
+      b: function(d) {
+        return locale_shortMonths[d.getMonth()];
+      },
+      B: function(d) {
+        return locale_months[d.getMonth()];
+      },
+      c: d3_time_format(locale_dateTime),
+      d: function(d, p) {
+        return d3_time_formatPad(d.getDate(), p, 2);
+      },
+      e: function(d, p) {
+        return d3_time_formatPad(d.getDate(), p, 2);
+      },
+      H: function(d, p) {
+        return d3_time_formatPad(d.getHours(), p, 2);
+      },
+      I: function(d, p) {
+        return d3_time_formatPad(d.getHours() % 12 || 12, p, 2);
+      },
+      j: function(d, p) {
+        return d3_time_formatPad(1 + d3_time.dayOfYear(d), p, 3);
+      },
+      L: function(d, p) {
+        return d3_time_formatPad(d.getMilliseconds(), p, 3);
+      },
+      m: function(d, p) {
+        return d3_time_formatPad(d.getMonth() + 1, p, 2);
+      },
+      M: function(d, p) {
+        return d3_time_formatPad(d.getMinutes(), p, 2);
+      },
+      p: function(d) {
+        return locale_periods[+(d.getHours() >= 12)];
+      },
+      S: function(d, p) {
+        return d3_time_formatPad(d.getSeconds(), p, 2);
+      },
+      U: function(d, p) {
+        return d3_time_formatPad(d3_time.sundayOfYear(d), p, 2);
+      },
+      w: function(d) {
+        return d.getDay();
+      },
+      W: function(d, p) {
+        return d3_time_formatPad(d3_time.mondayOfYear(d), p, 2);
+      },
+      x: d3_time_format(locale_date),
+      X: d3_time_format(locale_time),
+      y: function(d, p) {
+        return d3_time_formatPad(d.getFullYear() % 100, p, 2);
+      },
+      Y: function(d, p) {
+        return d3_time_formatPad(d.getFullYear() % 1e4, p, 4);
+      },
+      Z: d3_time_zone,
+      "%": function() {
+        return "%";
+      }
+    };
+    var d3_time_parsers = {
+      a: d3_time_parseWeekdayAbbrev,
+      A: d3_time_parseWeekday,
+      b: d3_time_parseMonthAbbrev,
+      B: d3_time_parseMonth,
+      c: d3_time_parseLocaleFull,
+      d: d3_time_parseDay,
+      e: d3_time_parseDay,
+      H: d3_time_parseHour24,
+      I: d3_time_parseHour24,
+      j: d3_time_parseDayOfYear,
+      L: d3_time_parseMilliseconds,
+      m: d3_time_parseMonthNumber,
+      M: d3_time_parseMinutes,
+      p: d3_time_parseAmPm,
+      S: d3_time_parseSeconds,
+      U: d3_time_parseWeekNumberSunday,
+      w: d3_time_parseWeekdayNumber,
+      W: d3_time_parseWeekNumberMonday,
+      x: d3_time_parseLocaleDate,
+      X: d3_time_parseLocaleTime,
+      y: d3_time_parseYear,
+      Y: d3_time_parseFullYear,
+      Z: d3_time_parseZone,
+      "%": d3_time_parseLiteralPercent
+    };
+    function d3_time_parseWeekdayAbbrev(date, string, i) {
+      d3_time_dayAbbrevRe.lastIndex = 0;
+      var n = d3_time_dayAbbrevRe.exec(string.substring(i));
+      return n ? (date.w = d3_time_dayAbbrevLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
+    }
+    function d3_time_parseWeekday(date, string, i) {
+      d3_time_dayRe.lastIndex = 0;
+      var n = d3_time_dayRe.exec(string.substring(i));
+      return n ? (date.w = d3_time_dayLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
+    }
+    function d3_time_parseMonthAbbrev(date, string, i) {
+      d3_time_monthAbbrevRe.lastIndex = 0;
+      var n = d3_time_monthAbbrevRe.exec(string.substring(i));
+      return n ? (date.m = d3_time_monthAbbrevLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
+    }
+    function d3_time_parseMonth(date, string, i) {
+      d3_time_monthRe.lastIndex = 0;
+      var n = d3_time_monthRe.exec(string.substring(i));
+      return n ? (date.m = d3_time_monthLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
+    }
+    function d3_time_parseLocaleFull(date, string, i) {
+      return d3_time_parse(date, d3_time_formats.c.toString(), string, i);
+    }
+    function d3_time_parseLocaleDate(date, string, i) {
+      return d3_time_parse(date, d3_time_formats.x.toString(), string, i);
+    }
+    function d3_time_parseLocaleTime(date, string, i) {
+      return d3_time_parse(date, d3_time_formats.X.toString(), string, i);
+    }
+    function d3_time_parseAmPm(date, string, i) {
+      var n = d3_time_periodLookup.get(string.substring(i, i += 2).toLowerCase());
+      return n == null ? -1 : (date.p = n, i);
+    }
+    return d3_time_format;
+  }
+  var d3_time_formatPads = {
+    "-": "",
+    _: " ",
+    "0": "0"
+  }, d3_time_numberRe = /^\s*\d+/, d3_time_percentRe = /^%/;
+  function d3_time_formatPad(value, fill, width) {
+    var sign = value < 0 ? "-" : "", string = (sign ? -value : value) + "", length = string.length;
+    return sign + (length < width ? new Array(width - length + 1).join(fill) + string : string);
+  }
+  function d3_time_formatRe(names) {
+    return new RegExp("^(?:" + names.map(d3.requote).join("|") + ")", "i");
+  }
+  function d3_time_formatLookup(names) {
+    var map = new d3_Map(), i = -1, n = names.length;
+    while (++i < n) map.set(names[i].toLowerCase(), i);
+    return map;
+  }
+  function d3_time_parseWeekdayNumber(date, string, i) {
+    d3_time_numberRe.lastIndex = 0;
+    var n = d3_time_numberRe.exec(string.substring(i, i + 1));
+    return n ? (date.w = +n[0], i + n[0].length) : -1;
+  }
+  function d3_time_parseWeekNumberSunday(date, string, i) {
+    d3_time_numberRe.lastIndex = 0;
+    var n = d3_time_numberRe.exec(string.substring(i));
+    return n ? (date.U = +n[0], i + n[0].length) : -1;
+  }
+  function d3_time_parseWeekNumberMonday(date, string, i) {
+    d3_time_numberRe.lastIndex = 0;
+    var n = d3_time_numberRe.exec(string.substring(i));
+    return n ? (date.W = +n[0], i + n[0].length) : -1;
+  }
+  function d3_time_parseFullYear(date, string, i) {
+    d3_time_numberRe.lastIndex = 0;
+    var n = d3_time_numberRe.exec(string.substring(i, i + 4));
+    return n ? (date.y = +n[0], i + n[0].length) : -1;
+  }
+  function d3_time_parseYear(date, string, i) {
+    d3_time_numberRe.lastIndex = 0;
+    var n = d3_time_numberRe.exec(string.substring(i, i + 2));
+    return n ? (date.y = d3_time_expandYear(+n[0]), i + n[0].length) : -1;
+  }
+  function d3_time_parseZone(date, string, i) {
+    return /^[+-]\d{4}$/.test(string = string.substring(i, i + 5)) ? (date.Z = +string, 
+    i + 5) : -1;
+  }
+  function d3_time_expandYear(d) {
+    return d + (d > 68 ? 1900 : 2e3);
+  }
+  function d3_time_parseMonthNumber(date, string, i) {
+    d3_time_numberRe.lastIndex = 0;
+    var n = d3_time_numberRe.exec(string.substring(i, i + 2));
+    return n ? (date.m = n[0] - 1, i + n[0].length) : -1;
+  }
+  function d3_time_parseDay(date, string, i) {
+    d3_time_numberRe.lastIndex = 0;
+    var n = d3_time_numberRe.exec(string.substring(i, i + 2));
+    return n ? (date.d = +n[0], i + n[0].length) : -1;
+  }
+  function d3_time_parseDayOfYear(date, string, i) {
+    d3_time_numberRe.lastIndex = 0;
+    var n = d3_time_numberRe.exec(string.substring(i, i + 3));
+    return n ? (date.j = +n[0], i + n[0].length) : -1;
+  }
+  function d3_time_parseHour24(date, string, i) {
+    d3_time_numberRe.lastIndex = 0;
+    var n = d3_time_numberRe.exec(string.substring(i, i + 2));
+    return n ? (date.H = +n[0], i + n[0].length) : -1;
+  }
+  function d3_time_parseMinutes(date, string, i) {
+    d3_time_numberRe.lastIndex = 0;
+    var n = d3_time_numberRe.exec(string.substring(i, i + 2));
+    return n ? (date.M = +n[0], i + n[0].length) : -1;
+  }
+  function d3_time_parseSeconds(date, string, i) {
+    d3_time_numberRe.lastIndex = 0;
+    var n = d3_time_numberRe.exec(string.substring(i, i + 2));
+    return n ? (date.S = +n[0], i + n[0].length) : -1;
+  }
+  function d3_time_parseMilliseconds(date, string, i) {
+    d3_time_numberRe.lastIndex = 0;
+    var n = d3_time_numberRe.exec(string.substring(i, i + 3));
+    return n ? (date.L = +n[0], i + n[0].length) : -1;
+  }
+  function d3_time_zone(d) {
+    var z = d.getTimezoneOffset(), zs = z > 0 ? "-" : "+", zh = ~~(abs(z) / 60), zm = abs(z) % 60;
+    return zs + d3_time_formatPad(zh, "0", 2) + d3_time_formatPad(zm, "0", 2);
+  }
+  function d3_time_parseLiteralPercent(date, string, i) {
+    d3_time_percentRe.lastIndex = 0;
+    var n = d3_time_percentRe.exec(string.substring(i, i + 1));
+    return n ? i + n[0].length : -1;
+  }
+  function d3_time_formatMulti(formats) {
+    var n = formats.length, i = -1;
+    while (++i < n) formats[i][0] = this(formats[i][0]);
+    return function(date) {
+      var i = 0, f = formats[i];
+      while (!f[1](date)) f = formats[++i];
+      return f[0](date);
+    };
+  }
+  d3.locale = function(locale) {
+    return {
+      numberFormat: d3_locale_numberFormat(locale),
+      timeFormat: d3_locale_timeFormat(locale)
+    };
+  };
+  var d3_locale_enUS = d3.locale({
+    decimal: ".",
+    thousands: ",",
+    grouping: [ 3 ],
+    currency: [ "$", "" ],
+    dateTime: "%a %b %e %X %Y",
+    date: "%m/%d/%Y",
+    time: "%H:%M:%S",
+    periods: [ "AM", "PM" ],
+    days: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ],
+    shortDays: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ],
+    months: [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ],
+    shortMonths: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ]
+  });
+  d3.format = d3_locale_enUS.numberFormat;
+  d3.geo = {};
+  function d3_adder() {}
+  d3_adder.prototype = {
+    s: 0,
+    t: 0,
+    add: function(y) {
+      d3_adderSum(y, this.t, d3_adderTemp);
+      d3_adderSum(d3_adderTemp.s, this.s, this);
+      if (this.s) this.t += d3_adderTemp.t; else this.s = d3_adderTemp.t;
+    },
+    reset: function() {
+      this.s = this.t = 0;
+    },
+    valueOf: function() {
+      return this.s;
+    }
+  };
+  var d3_adderTemp = new d3_adder();
+  function d3_adderSum(a, b, o) {
+    var x = o.s = a + b, bv = x - a, av = x - bv;
+    o.t = a - av + (b - bv);
+  }
+  d3.geo.stream = function(object, listener) {
+    if (object && d3_geo_streamObjectType.hasOwnProperty(object.type)) {
+      d3_geo_streamObjectType[object.type](object, listener);
+    } else {
+      d3_geo_streamGeometry(object, listener);
+    }
+  };
+  function d3_geo_streamGeometry(geometry, listener) {
+    if (geometry && d3_geo_streamGeometryType.hasOwnProperty(geometry.type)) {
+      d3_geo_streamGeometryType[geometry.type](geometry, listener);
+    }
+  }
+  var d3_geo_streamObjectType = {
+    Feature: function(feature, listener) {
+      d3_geo_streamGeometry(feature.geometry, listener);
+    },
+    FeatureCollection: function(object, listener) {
+      var features = object.features, i = -1, n = features.length;
+      while (++i < n) d3_geo_streamGeometry(features[i].geometry, listener);
+    }
+  };
+  var d3_geo_streamGeometryType = {
+    Sphere: function(object, listener) {
+      listener.sphere();
+    },
+    Point: function(object, listener) {
+      object = object.coordinates;
+      listener.point(object[0], object[1], object[2]);
+    },
+    MultiPoint: function(object, listener) {
+      var coordinates = object.coordinates, i = -1, n = coordinates.length;
+      while (++i < n) object = coordinates[i], listener.point(object[0], object[1], object[2]);
+    },
+    LineString: function(object, listener) {
+      d3_geo_streamLine(object.coordinates, listener, 0);
+    },
+    MultiLineString: function(object, listener) {
+      var coordinates = object.coordinates, i = -1, n = coordinates.length;
+      while (++i < n) d3_geo_streamLine(coordinates[i], listener, 0);
+    },
+    Polygon: function(object, listener) {
+      d3_geo_streamPolygon(object.coordinates, listener);
+    },
+    MultiPolygon: function(object, listener) {
+      var coordinates = object.coordinates, i = -1, n = coordinates.length;
+      while (++i < n) d3_geo_streamPolygon(coordinates[i], listener);
+    },
+    GeometryCollection: function(object, listener) {
+      var geometries = object.geometries, i = -1, n = geometries.length;
+      while (++i < n) d3_geo_streamGeometry(geometries[i], listener);
+    }
+  };
+  function d3_geo_streamLine(coordinates, listener, closed) {
+    var i = -1, n = coordinates.length - closed, coordinate;
+    listener.lineStart();
+    while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1], coordinate[2]);
+    listener.lineEnd();
+  }
+  function d3_geo_streamPolygon(coordinates, listener) {
+    var i = -1, n = coordinates.length;
+    listener.polygonStart();
+    while (++i < n) d3_geo_streamLine(coordinates[i], listener, 1);
+    listener.polygonEnd();
+  }
+  d3.geo.area = function(object) {
+    d3_geo_areaSum = 0;
+    d3.geo.stream(object, d3_geo_area);
+    return d3_geo_areaSum;
+  };
+  var d3_geo_areaSum, d3_geo_areaRingSum = new d3_adder();
+  var d3_geo_area = {
+    sphere: function() {
+      d3_geo_areaSum += 4 * π;
+    },
+    point: d3_noop,
+    lineStart: d3_noop,
+    lineEnd: d3_noop,
+    polygonStart: function() {
+      d3_geo_areaRingSum.reset();
+      d3_geo_area.lineStart = d3_geo_areaRingStart;
+    },
+    polygonEnd: function() {
+      var area = 2 * d3_geo_areaRingSum;
+      d3_geo_areaSum += area < 0 ? 4 * π + area : area;
+      d3_geo_area.lineStart = d3_geo_area.lineEnd = d3_geo_area.point = d3_noop;
+    }
+  };
+  function d3_geo_areaRingStart() {
+    var λ00, φ00, λ0, cosφ0, sinφ0;
+    d3_geo_area.point = function(λ, φ) {
+      d3_geo_area.point = nextPoint;
+      λ0 = (λ00 = λ) * d3_radians, cosφ0 = Math.cos(φ = (φ00 = φ) * d3_radians / 2 + π / 4), 
+      sinφ0 = Math.sin(φ);
+    };
+    function nextPoint(λ, φ) {
+      λ *= d3_radians;
+      φ = φ * d3_radians / 2 + π / 4;
+      var dλ = λ - λ0, sdλ = dλ >= 0 ? 1 : -1, adλ = sdλ * dλ, cosφ = Math.cos(φ), sinφ = Math.sin(φ), k = sinφ0 * sinφ, u = cosφ0 * cosφ + k * Math.cos(adλ), v = k * sdλ * Math.sin(adλ);
+      d3_geo_areaRingSum.add(Math.atan2(v, u));
+      λ0 = λ, cosφ0 = cosφ, sinφ0 = sinφ;
+    }
+    d3_geo_area.lineEnd = function() {
+      nextPoint(λ00, φ00);
+    };
+  }
+  function d3_geo_cartesian(spherical) {
+    var λ = spherical[0], φ = spherical[1], cosφ = Math.cos(φ);
+    return [ cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ) ];
+  }
+  function d3_geo_cartesianDot(a, b) {
+    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+  }
+  function d3_geo_cartesianCross(a, b) {
+    return [ a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0] ];
+  }
+  function d3_geo_cartesianAdd(a, b) {
+    a[0] += b[0];
+    a[1] += b[1];
+    a[2] += b[2];
+  }
+  function d3_geo_cartesianScale(vector, k) {
+    return [ vector[0] * k, vector[1] * k, vector[2] * k ];
+  }
+  function d3_geo_cartesianNormalize(d) {
+    var l = Math.sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
+    d[0] /= l;
+    d[1] /= l;
+    d[2] /= l;
+  }
+  function d3_geo_spherical(cartesian) {
+    return [ Math.atan2(cartesian[1], cartesian[0]), d3_asin(cartesian[2]) ];
+  }
+  function d3_geo_sphericalEqual(a, b) {
+    return abs(a[0] - b[0]) < ε && abs(a[1] - b[1]) < ε;
+  }
+  d3.geo.bounds = function() {
+    var λ0, φ0, λ1, φ1, λ_, λ__, φ__, p0, dλSum, ranges, range;
+    var bound = {
+      point: point,
+      lineStart: lineStart,
+      lineEnd: lineEnd,
+      polygonStart: function() {
+        bound.point = ringPoint;
+        bound.lineStart = ringStart;
+        bound.lineEnd = ringEnd;
+        dλSum = 0;
+        d3_geo_area.polygonStart();
+      },
+      polygonEnd: function() {
+        d3_geo_area.polygonEnd();
+        bound.point = point;
+        bound.lineStart = lineStart;
+        bound.lineEnd = lineEnd;
+        if (d3_geo_areaRingSum < 0) λ0 = -(λ1 = 180), φ0 = -(φ1 = 90); else if (dλSum > ε) φ1 = 90; else if (dλSum < -ε) φ0 = -90;
+        range[0] = λ0, range[1] = λ1;
+      }
+    };
+    function point(λ, φ) {
+      ranges.push(range = [ λ0 = λ, λ1 = λ ]);
+      if (φ < φ0) φ0 = φ;
+      if (φ > φ1) φ1 = φ;
+    }
+    function linePoint(λ, φ) {
+      var p = d3_geo_cartesian([ λ * d3_radians, φ * d3_radians ]);
+      if (p0) {
+        var normal = d3_geo_cartesianCross(p0, p), equatorial = [ normal[1], -normal[0], 0 ], inflection = d3_geo_cartesianCross(equatorial, normal);
+        d3_geo_cartesianNormalize(inflection);
+        inflection = d3_geo_spherical(inflection);
+        var dλ = λ - λ_, s = dλ > 0 ? 1 : -1, λi = inflection[0] * d3_degrees * s, antimeridian = abs(dλ) > 180;
+        if (antimeridian ^ (s * λ_ < λi && λi < s * λ)) {
+          var φi = inflection[1] * d3_degrees;
+          if (φi > φ1) φ1 = φi;
+        } else if (λi = (λi + 360) % 360 - 180, antimeridian ^ (s * λ_ < λi && λi < s * λ)) {
+          var φi = -inflection[1] * d3_degrees;
+          if (φi < φ0) φ0 = φi;
+        } else {
+          if (φ < φ0) φ0 = φ;
+          if (φ > φ1) φ1 = φ;
+        }
+        if (antimeridian) {
+          if (λ < λ_) {
+            if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ;
+          } else {
+            if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ;
+          }
+        } else {
+          if (λ1 >= λ0) {
+            if (λ < λ0) λ0 = λ;
+            if (λ > λ1) λ1 = λ;
+          } else {
+            if (λ > λ_) {
+              if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ;
+            } else {
+              if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ;
+            }
+          }
+        }
+      } else {
+        point(λ, φ);
+      }
+      p0 = p, λ_ = λ;
+    }
+    function lineStart() {
+      bound.point = linePoint;
+    }
+    function lineEnd() {
+      range[0] = λ0, range[1] = λ1;
+      bound.point = point;
+      p0 = null;
+    }
+    function ringPoint(λ, φ) {
+      if (p0) {
+        var dλ = λ - λ_;
+        dλSum += abs(dλ) > 180 ? dλ + (dλ > 0 ? 360 : -360) : dλ;
+      } else λ__ = λ, φ__ = φ;
+      d3_geo_area.point(λ, φ);
+      linePoint(λ, φ);
+    }
+    function ringStart() {
+      d3_geo_area.lineStart();
+    }
+    function ringEnd() {
+      ringPoint(λ__, φ__);
+      d3_geo_area.lineEnd();
+      if (abs(dλSum) > ε) λ0 = -(λ1 = 180);
+      range[0] = λ0, range[1] = λ1;
+      p0 = null;
+    }
+    function angle(λ0, λ1) {
+      return (λ1 -= λ0) < 0 ? λ1 + 360 : λ1;
+    }
+    function compareRanges(a, b) {
+      return a[0] - b[0];
+    }
+    function withinRange(x, range) {
+      return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x;
+    }
+    return function(feature) {
+      φ1 = λ1 = -(λ0 = φ0 = Infinity);
+      ranges = [];
+      d3.geo.stream(feature, bound);
+      var n = ranges.length;
+      if (n) {
+        ranges.sort(compareRanges);
+        for (var i = 1, a = ranges[0], b, merged = [ a ]; i < n; ++i) {
+          b = ranges[i];
+          if (withinRange(b[0], a) || withinRange(b[1], a)) {
+            if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1];
+            if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0];
+          } else {
+            merged.push(a = b);
+          }
+        }
+        var best = -Infinity, dλ;
+        for (var n = merged.length - 1, i = 0, a = merged[n], b; i <= n; a = b, ++i) {
+          b = merged[i];
+          if ((dλ = angle(a[1], b[0])) > best) best = dλ, λ0 = b[0], λ1 = a[1];
+        }
+      }
+      ranges = range = null;
+      return λ0 === Infinity || φ0 === Infinity ? [ [ NaN, NaN ], [ NaN, NaN ] ] : [ [ λ0, φ0 ], [ λ1, φ1 ] ];
+    };
+  }();
+  d3.geo.centroid = function(object) {
+    d3_geo_centroidW0 = d3_geo_centroidW1 = d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 = d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 = d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0;
+    d3.geo.stream(object, d3_geo_centroid);
+    var x = d3_geo_centroidX2, y = d3_geo_centroidY2, z = d3_geo_centroidZ2, m = x * x + y * y + z * z;
+    if (m < ε2) {
+      x = d3_geo_centroidX1, y = d3_geo_centroidY1, z = d3_geo_centroidZ1;
+      if (d3_geo_centroidW1 < ε) x = d3_geo_centroidX0, y = d3_geo_centroidY0, z = d3_geo_centroidZ0;
+      m = x * x + y * y + z * z;
+      if (m < ε2) return [ NaN, NaN ];
+    }
+    return [ Math.atan2(y, x) * d3_degrees, d3_asin(z / Math.sqrt(m)) * d3_degrees ];
+  };
+  var d3_geo_centroidW0, d3_geo_centroidW1, d3_geo_centroidX0, d3_geo_centroidY0, d3_geo_centroidZ0, d3_geo_centroidX1, d3_geo_centroidY1, d3_geo_centroidZ1, d3_geo_centroidX2, d3_geo_centroidY2, d3_geo_centroidZ2;
+  var d3_geo_centroid = {
+    sphere: d3_noop,
+    point: d3_geo_centroidPoint,
+    lineStart: d3_geo_centroidLineStart,
+    lineEnd: d3_geo_centroidLineEnd,
+    polygonStart: function() {
+      d3_geo_centroid.lineStart = d3_geo_centroidRingStart;
+    },
+    polygonEnd: function() {
+      d3_geo_centroid.lineStart = d3_geo_centroidLineStart;
+    }
+  };
+  function d3_geo_centroidPoint(λ, φ) {
+    λ *= d3_radians;
+    var cosφ = Math.cos(φ *= d3_radians);
+    d3_geo_centroidPointXYZ(cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ));
+  }
+  function d3_geo_centroidPointXYZ(x, y, z) {
+    ++d3_geo_centroidW0;
+    d3_geo_centroidX0 += (x - d3_geo_centroidX0) / d3_geo_centroidW0;
+    d3_geo_centroidY0 += (y - d3_geo_centroidY0) / d3_geo_centroidW0;
+    d3_geo_centroidZ0 += (z - d3_geo_centroidZ0) / d3_geo_centroidW0;
+  }
+  function d3_geo_centroidLineStart() {
+    var x0, y0, z0;
+    d3_geo_centroid.point = function(λ, φ) {
+      λ *= d3_radians;
+      var cosφ = Math.cos(φ *= d3_radians);
+      x0 = cosφ * Math.cos(λ);
+      y0 = cosφ * Math.sin(λ);
+      z0 = Math.sin(φ);
+      d3_geo_centroid.point = nextPoint;
+      d3_geo_centroidPointXYZ(x0, y0, z0);
+    };
+    function nextPoint(λ, φ) {
+      λ *= d3_radians;
+      var cosφ = Math.cos(φ *= d3_radians), x = cosφ * Math.cos(λ), y = cosφ * Math.sin(λ), z = Math.sin(φ), w = Math.atan2(Math.sqrt((w = y0 * z - z0 * y) * w + (w = z0 * x - x0 * z) * w + (w = x0 * y - y0 * x) * w), x0 * x + y0 * y + z0 * z);
+      d3_geo_centroidW1 += w;
+      d3_geo_centroidX1 += w * (x0 + (x0 = x));
+      d3_geo_centroidY1 += w * (y0 + (y0 = y));
+      d3_geo_centroidZ1 += w * (z0 + (z0 = z));
+      d3_geo_centroidPointXYZ(x0, y0, z0);
+    }
+  }
+  function d3_geo_centroidLineEnd() {
+    d3_geo_centroid.point = d3_geo_centroidPoint;
+  }
+  function d3_geo_centroidRingStart() {
+    var λ00, φ00, x0, y0, z0;
+    d3_geo_centroid.point = function(λ, φ) {
+      λ00 = λ, φ00 = φ;
+      d3_geo_centroid.point = nextPoint;
+      λ *= d3_radians;
+      var cosφ = Math.cos(φ *= d3_radians);
+      x0 = cosφ * Math.cos(λ);
+      y0 = cosφ * Math.sin(λ);
+      z0 = Math.sin(φ);
+      d3_geo_centroidPointXYZ(x0, y0, z0);
+    };
+    d3_geo_centroid.lineEnd = function() {
+      nextPoint(λ00, φ00);
+      d3_geo_centroid.lineEnd = d3_geo_centroidLineEnd;
+      d3_geo_centroid.point = d3_geo_centroidPoint;
+    };
+    function nextPoint(λ, φ) {
+      λ *= d3_radians;
+      var cosφ = Math.cos(φ *= d3_radians), x = cosφ * Math.cos(λ), y = cosφ * Math.sin(λ), z = Math.sin(φ), cx = y0 * z - z0 * y, cy = z0 * x - x0 * z, cz = x0 * y - y0 * x, m = Math.sqrt(cx * cx + cy * cy + cz * cz), u = x0 * x + y0 * y + z0 * z, v = m && -d3_acos(u) / m, w = Math.atan2(m, u);
+      d3_geo_centroidX2 += v * cx;
+      d3_geo_centroidY2 += v * cy;
+      d3_geo_centroidZ2 += v * cz;
+      d3_geo_centroidW1 += w;
+      d3_geo_centroidX1 += w * (x0 + (x0 = x));
+      d3_geo_centroidY1 += w * (y0 + (y0 = y));
+      d3_geo_centroidZ1 += w * (z0 + (z0 = z));
+      d3_geo_centroidPointXYZ(x0, y0, z0);
+    }
+  }
+  function d3_true() {
+    return true;
+  }
+  function d3_geo_clipPolygon(segments, compare, clipStartInside, interpolate, listener) {
+    var subject = [], clip = [];
+    segments.forEach(function(segment) {
+      if ((n = segment.length - 1) <= 0) return;
+      var n, p0 = segment[0], p1 = segment[n];
+      if (d3_geo_sphericalEqual(p0, p1)) {
+        listener.lineStart();
+        for (var i = 0; i < n; ++i) listener.point((p0 = segment[i])[0], p0[1]);
+        listener.lineEnd();
+        return;
+      }
+      var a = new d3_geo_clipPolygonIntersection(p0, segment, null, true), b = new d3_geo_clipPolygonIntersection(p0, null, a, false);
+      a.o = b;
+      subject.push(a);
+      clip.push(b);
+      a = new d3_geo_clipPolygonIntersection(p1, segment, null, false);
+      b = new d3_geo_clipPolygonIntersection(p1, null, a, true);
+      a.o = b;
+      subject.push(a);
+      clip.push(b);
+    });
+    clip.sort(compare);
+    d3_geo_clipPolygonLinkCircular(subject);
+    d3_geo_clipPolygonLinkCircular(clip);
+    if (!subject.length) return;
+    for (var i = 0, entry = clipStartInside, n = clip.length; i < n; ++i) {
+      clip[i].e = entry = !entry;
+    }
+    var start = subject[0], points, point;
+    while (1) {
+      var current = start, isSubject = true;
+      while (current.v) if ((current = current.n) === start) return;
+      points = current.z;
+      listener.lineStart();
+      do {
+        current.v = current.o.v = true;
+        if (current.e) {
+          if (isSubject) {
+            for (var i = 0, n = points.length; i < n; ++i) listener.point((point = points[i])[0], point[1]);
+          } else {
+            interpolate(current.x, current.n.x, 1, listener);
+          }
+          current = current.n;
+        } else {
+          if (isSubject) {
+            points = current.p.z;
+            for (var i = points.length - 1; i >= 0; --i) listener.point((point = points[i])[0], point[1]);
+          } else {
+            interpolate(current.x, current.p.x, -1, listener);
+          }
+          current = current.p;
+        }
+        current = current.o;
+        points = current.z;
+        isSubject = !isSubject;
+      } while (!current.v);
+      listener.lineEnd();
+    }
+  }
+  function d3_geo_clipPolygonLinkCircular(array) {
+    if (!(n = array.length)) return;
+    var n, i = 0, a = array[0], b;
+    while (++i < n) {
+      a.n = b = array[i];
+      b.p = a;
+      a = b;
+    }
+    a.n = b = array[0];
+    b.p = a;
+  }
+  function d3_geo_clipPolygonIntersection(point, points, other, entry) {
+    this.x = point;
+    this.z = points;
+    this.o = other;
+    this.e = entry;
+    this.v = false;
+    this.n = this.p = null;
+  }
+  function d3_geo_clip(pointVisible, clipLine, interpolate, clipStart) {
+    return function(rotate, listener) {
+      var line = clipLine(listener), rotatedClipStart = rotate.invert(clipStart[0], clipStart[1]);
+      var clip = {
+        point: point,
+        lineStart: lineStart,
+        lineEnd: lineEnd,
+        polygonStart: function() {
+          clip.point = pointRing;
+          clip.lineStart = ringStart;
+          clip.lineEnd = ringEnd;
+          segments = [];
+          polygon = [];
+          listener.polygonStart();
+        },
+        polygonEnd: function() {
+          clip.point = point;
+          clip.lineStart = lineStart;
+          clip.lineEnd = lineEnd;
+          segments = d3.merge(segments);
+          var clipStartInside = d3_geo_pointInPolygon(rotatedClipStart, polygon);
+          if (segments.length) {
+            d3_geo_clipPolygon(segments, d3_geo_clipSort, clipStartInside, interpolate, listener);
+          } else if (clipStartInside) {
+            listener.lineStart();
+            interpolate(null, null, 1, listener);
+            listener.lineEnd();
+          }
+          listener.polygonEnd();
+          segments = polygon = null;
+        },
+        sphere: function() {
+          listener.polygonStart();
+          listener.lineStart();
+          interpolate(null, null, 1, listener);
+          listener.lineEnd();
+          listener.polygonEnd();
+        }
+      };
+      function point(λ, φ) {
+        var point = rotate(λ, φ);
+        if (pointVisible(λ = point[0], φ = point[1])) listener.point(λ, φ);
+      }
+      function pointLine(λ, φ) {
+        var point = rotate(λ, φ);
+        line.point(point[0], point[1]);
+      }
+      function lineStart() {
+        clip.point = pointLine;
+        line.lineStart();
+      }
+      function lineEnd() {
+        clip.point = point;
+        line.lineEnd();
+      }
+      var segments;
+      var buffer = d3_geo_clipBufferListener(), ringListener = clipLine(buffer), polygon, ring;
+      function pointRing(λ, φ) {
+        ring.push([ λ, φ ]);
+        var point = rotate(λ, φ);
+        ringListener.point(point[0], point[1]);
+      }
+      function ringStart() {
+        ringListener.lineStart();
+        ring = [];
+      }
+      function ringEnd() {
+        pointRing(ring[0][0], ring[0][1]);
+        ringListener.lineEnd();
+        var clean = ringListener.clean(), ringSegments = buffer.buffer(), segment, n = ringSegments.length;
+        ring.pop();
+        polygon.push(ring);
+        ring = null;
+        if (!n) return;
+        if (clean & 1) {
+          segment = ringSegments[0];
+          var n = segment.length - 1, i = -1, point;
+          listener.lineStart();
+          while (++i < n) listener.point((point = segment[i])[0], point[1]);
+          listener.lineEnd();
+          return;
+        }
+        if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift()));
+        segments.push(ringSegments.filter(d3_geo_clipSegmentLength1));
+      }
+      return clip;
+    };
+  }
+  function d3_geo_clipSegmentLength1(segment) {
+    return segment.length > 1;
+  }
+  function d3_geo_clipBufferListener() {
+    var lines = [], line;
+    return {
+      lineStart: function() {
+        lines.push(line = []);
+      },
+      point: function(λ, φ) {
+        line.push([ λ, φ ]);
+      },
+      lineEnd: d3_noop,
+      buffer: function() {
+        var buffer = lines;
+        lines = [];
+        line = null;
+        return buffer;
+      },
+      rejoin: function() {
+        if (lines.length > 1) lines.push(lines.pop().concat(lines.shift()));
+      }
+    };
+  }
+  function d3_geo_clipSort(a, b) {
+    return ((a = a.x)[0] < 0 ? a[1] - halfπ - ε : halfπ - a[1]) - ((b = b.x)[0] < 0 ? b[1] - halfπ - ε : halfπ - b[1]);
+  }
+  function d3_geo_pointInPolygon(point, polygon) {
+    var meridian = point[0], parallel = point[1], meridianNormal = [ Math.sin(meridian), -Math.cos(meridian), 0 ], polarAngle = 0, winding = 0;
+    d3_geo_areaRingSum.reset();
+    for (var i = 0, n = polygon.length; i < n; ++i) {
+      var ring = polygon[i], m = ring.length;
+      if (!m) continue;
+      var point0 = ring[0], λ0 = point0[0], φ0 = point0[1] / 2 + π / 4, sinφ0 = Math.sin(φ0), cosφ0 = Math.cos(φ0), j = 1;
+      while (true) {
+        if (j === m) j = 0;
+        point = ring[j];
+        var λ = point[0], φ = point[1] / 2 + π / 4, sinφ = Math.sin(φ), cosφ = Math.cos(φ), dλ = λ - λ0, sdλ = dλ >= 0 ? 1 : -1, adλ = sdλ * dλ, antimeridian = adλ > π, k = sinφ0 * sinφ;
+        d3_geo_areaRingSum.add(Math.atan2(k * sdλ * Math.sin(adλ), cosφ0 * cosφ + k * Math.cos(adλ)));
+        polarAngle += antimeridian ? dλ + sdλ * τ : dλ;
+        if (antimeridian ^ λ0 >= meridian ^ λ >= meridian) {
+          var arc = d3_geo_cartesianCross(d3_geo_cartesian(point0), d3_geo_cartesian(point));
+          d3_geo_cartesianNormalize(arc);
+          var intersection = d3_geo_cartesianCross(meridianNormal, arc);
+          d3_geo_cartesianNormalize(intersection);
+          var φarc = (antimeridian ^ dλ >= 0 ? -1 : 1) * d3_asin(intersection[2]);
+          if (parallel > φarc || parallel === φarc && (arc[0] || arc[1])) {
+            winding += antimeridian ^ dλ >= 0 ? 1 : -1;
+          }
+        }
+        if (!j++) break;
+        λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ, point0 = point;
+      }
+    }
+    return (polarAngle < -ε || polarAngle < ε && d3_geo_areaRingSum < 0) ^ winding & 1;
+  }
+  var d3_geo_clipAntimeridian = d3_geo_clip(d3_true, d3_geo_clipAntimeridianLine, d3_geo_clipAntimeridianInterpolate, [ -π, -π / 2 ]);
+  function d3_geo_clipAntimeridianLine(listener) {
+    var λ0 = NaN, φ0 = NaN, sλ0 = NaN, clean;
+    return {
+      lineStart: function() {
+        listener.lineStart();
+        clean = 1;
+      },
+      point: function(λ1, φ1) {
+        var sλ1 = λ1 > 0 ? π : -π, dλ = abs(λ1 - λ0);
+        if (abs(dλ - π) < ε) {
+          listener.point(λ0, φ0 = (φ0 + φ1) / 2 > 0 ? halfπ : -halfπ);
+          listener.point(sλ0, φ0);
+          listener.lineEnd();
+          listener.lineStart();
+          listener.point(sλ1, φ0);
+          listener.point(λ1, φ0);
+          clean = 0;
+        } else if (sλ0 !== sλ1 && dλ >= π) {
+          if (abs(λ0 - sλ0) < ε) λ0 -= sλ0 * ε;
+          if (abs(λ1 - sλ1) < ε) λ1 -= sλ1 * ε;
+          φ0 = d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1);
+          listener.point(sλ0, φ0);
+          listener.lineEnd();
+          listener.lineStart();
+          listener.point(sλ1, φ0);
+          clean = 0;
+        }
+        listener.point(λ0 = λ1, φ0 = φ1);
+        sλ0 = sλ1;
+      },
+      lineEnd: function() {
+        listener.lineEnd();
+        λ0 = φ0 = NaN;
+      },
+      clean: function() {
+        return 2 - clean;
+      }
+    };
+  }
+  function d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1) {
+    var cosφ0, cosφ1, sinλ0_λ1 = Math.sin(λ0 - λ1);
+    return abs(sinλ0_λ1) > ε ? Math.atan((Math.sin(φ0) * (cosφ1 = Math.cos(φ1)) * Math.sin(λ1) - Math.sin(φ1) * (cosφ0 = Math.cos(φ0)) * Math.sin(λ0)) / (cosφ0 * cosφ1 * sinλ0_λ1)) : (φ0 + φ1) / 2;
+  }
+  function d3_geo_clipAntimeridianInterpolate(from, to, direction, listener) {
+    var φ;
+    if (from == null) {
+      φ = direction * halfπ;
+      listener.point(-π, φ);
+      listener.point(0, φ);
+      listener.point(π, φ);
+      listener.point(π, 0);
+      listener.point(π, -φ);
+      listener.point(0, -φ);
+      listener.point(-π, -φ);
+      listener.point(-π, 0);
+      listener.point(-π, φ);
+    } else if (abs(from[0] - to[0]) > ε) {
+      var s = from[0] < to[0] ? π : -π;
+      φ = direction * s / 2;
+      listener.point(-s, φ);
+      listener.point(0, φ);
+      listener.point(s, φ);
+    } else {
+      listener.point(to[0], to[1]);
+    }
+  }
+  function d3_geo_clipCircle(radius) {
+    var cr = Math.cos(radius), smallRadius = cr > 0, notHemisphere = abs(cr) > ε, interpolate = d3_geo_circleInterpolate(radius, 6 * d3_radians);
+    return d3_geo_clip(visible, clipLine, interpolate, smallRadius ? [ 0, -radius ] : [ -π, radius - π ]);
+    function visible(λ, φ) {
+      return Math.cos(λ) * Math.cos(φ) > cr;
+    }
+    function clipLine(listener) {
+      var point0, c0, v0, v00, clean;
+      return {
+        lineStart: function() {
+          v00 = v0 = false;
+          clean = 1;
+        },
+        point: function(λ, φ) {
+          var point1 = [ λ, φ ], point2, v = visible(λ, φ), c = smallRadius ? v ? 0 : code(λ, φ) : v ? code(λ + (λ < 0 ? π : -π), φ) : 0;
+          if (!point0 && (v00 = v0 = v)) listener.lineStart();
+          if (v !== v0) {
+            point2 = intersect(point0, point1);
+            if (d3_geo_sphericalEqual(point0, point2) || d3_geo_sphericalEqual(point1, point2)) {
+              point1[0] += ε;
+              point1[1] += ε;
+              v = visible(point1[0], point1[1]);
+            }
+          }
+          if (v !== v0) {
+            clean = 0;
+            if (v) {
+              listener.lineStart();
+              point2 = intersect(point1, point0);
+              listener.point(point2[0], point2[1]);
+            } else {
+              point2 = intersect(point0, point1);
+              listener.point(point2[0], point2[1]);
+              listener.lineEnd();
+            }
+            point0 = point2;
+          } else if (notHemisphere && point0 && smallRadius ^ v) {
+            var t;
+            if (!(c & c0) && (t = intersect(point1, point0, true))) {
+              clean = 0;
+              if (smallRadius) {
+                listener.lineStart();
+                listener.point(t[0][0], t[0][1]);
+                listener.point(t[1][0], t[1][1]);
+                listener.lineEnd();
+              } else {
+                listener.point(t[1][0], t[1][1]);
+                listener.lineEnd();
+                listener.lineStart();
+                listener.point(t[0][0], t[0][1]);
+              }
+            }
+          }
+          if (v && (!point0 || !d3_geo_sphericalEqual(point0, point1))) {
+            listener.point(point1[0], point1[1]);
+          }
+          point0 = point1, v0 = v, c0 = c;
+        },
+        lineEnd: function() {
+          if (v0) listener.lineEnd();
+          point0 = null;
+        },
+        clean: function() {
+          return clean | (v00 && v0) << 1;
+        }
+      };
+    }
+    function intersect(a, b, two) {
+      var pa = d3_geo_cartesian(a), pb = d3_geo_cartesian(b);
+      var n1 = [ 1, 0, 0 ], n2 = d3_geo_cartesianCross(pa, pb), n2n2 = d3_geo_cartesianDot(n2, n2), n1n2 = n2[0], determinant = n2n2 - n1n2 * n1n2;
+      if (!determinant) return !two && a;
+      var c1 = cr * n2n2 / determinant, c2 = -cr * n1n2 / determinant, n1xn2 = d3_geo_cartesianCross(n1, n2), A = d3_geo_cartesianScale(n1, c1), B = d3_geo_cartesianScale(n2, c2);
+      d3_geo_cartesianAdd(A, B);
+      var u = n1xn2, w = d3_geo_cartesianDot(A, u), uu = d3_geo_cartesianDot(u, u), t2 = w * w - uu * (d3_geo_cartesianDot(A, A) - 1);
+      if (t2 < 0) return;
+      var t = Math.sqrt(t2), q = d3_geo_cartesianScale(u, (-w - t) / uu);
+      d3_geo_cartesianAdd(q, A);
+      q = d3_geo_spherical(q);
+      if (!two) return q;
+      var λ0 = a[0], λ1 = b[0], φ0 = a[1], φ1 = b[1], z;
+      if (λ1 < λ0) z = λ0, λ0 = λ1, λ1 = z;
+      var δλ = λ1 - λ0, polar = abs(δλ - π) < ε, meridian = polar || δλ < ε;
+      if (!polar && φ1 < φ0) z = φ0, φ0 = φ1, φ1 = z;
+      if (meridian ? polar ? φ0 + φ1 > 0 ^ q[1] < (abs(q[0] - λ0) < ε ? φ0 : φ1) : φ0 <= q[1] && q[1] <= φ1 : δλ > π ^ (λ0 <= q[0] && q[0] <= λ1)) {
+        var q1 = d3_geo_cartesianScale(u, (-w + t) / uu);
+        d3_geo_cartesianAdd(q1, A);
+        return [ q, d3_geo_spherical(q1) ];
+      }
+    }
+    function code(λ, φ) {
+      var r = smallRadius ? radius : π - radius, code = 0;
+      if (λ < -r) code |= 1; else if (λ > r) code |= 2;
+      if (φ < -r) code |= 4; else if (φ > r) code |= 8;
+      return code;
+    }
+  }
+  function d3_geom_clipLine(x0, y0, x1, y1) {
+    return function(line) {
+      var a = line.a, b = line.b, ax = a.x, ay = a.y, bx = b.x, by = b.y, t0 = 0, t1 = 1, dx = bx - ax, dy = by - ay, r;
+      r = x0 - ax;
+      if (!dx && r > 0) return;
+      r /= dx;
+      if (dx < 0) {
+        if (r < t0) return;
+        if (r < t1) t1 = r;
+      } else if (dx > 0) {
+        if (r > t1) return;
+        if (r > t0) t0 = r;
+      }
+      r = x1 - ax;
+      if (!dx && r < 0) return;
+      r /= dx;
+      if (dx < 0) {
+        if (r > t1) return;
+        if (r > t0) t0 = r;
+      } else if (dx > 0) {
+        if (r < t0) return;
+        if (r < t1) t1 = r;
+      }
+      r = y0 - ay;
+      if (!dy && r > 0) return;
+      r /= dy;
+      if (dy < 0) {
+        if (r < t0) return;
+        if (r < t1) t1 = r;
+      } else if (dy > 0) {
+        if (r > t1) return;
+        if (r > t0) t0 = r;
+      }
+      r = y1 - ay;
+      if (!dy && r < 0) return;
+      r /= dy;
+      if (dy < 0) {
+        if (r > t1) return;
+        if (r > t0) t0 = r;
+      } else if (dy > 0) {
+        if (r < t0) return;
+        if (r < t1) t1 = r;
+      }
+      if (t0 > 0) line.a = {
+        x: ax + t0 * dx,
+        y: ay + t0 * dy
+      };
+      if (t1 < 1) line.b = {
+        x: ax + t1 * dx,
+        y: ay + t1 * dy
+      };
+      return line;
+    };
+  }
+  var d3_geo_clipExtentMAX = 1e9;
+  d3.geo.clipExtent = function() {
+    var x0, y0, x1, y1, stream, clip, clipExtent = {
+      stream: function(output) {
+        if (stream) stream.valid = false;
+        stream = clip(output);
+        stream.valid = true;
+        return stream;
+      },
+      extent: function(_) {
+        if (!arguments.length) return [ [ x0, y0 ], [ x1, y1 ] ];
+        clip = d3_geo_clipExtent(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]);
+        if (stream) stream.valid = false, stream = null;
+        return clipExtent;
+      }
+    };
+    return clipExtent.extent([ [ 0, 0 ], [ 960, 500 ] ]);
+  };
+  function d3_geo_clipExtent(x0, y0, x1, y1) {
+    return function(listener) {
+      var listener_ = listener, bufferListener = d3_geo_clipBufferListener(), clipLine = d3_geom_clipLine(x0, y0, x1, y1), segments, polygon, ring;
+      var clip = {
+        point: point,
+        lineStart: lineStart,
+        lineEnd: lineEnd,
+        polygonStart: function() {
+          listener = bufferListener;
+          segments = [];
+          polygon = [];
+          clean = true;
+        },
+        polygonEnd: function() {
+          listener = listener_;
+          segments = d3.merge(segments);
+          var clipStartInside = insidePolygon([ x0, y1 ]), inside = clean && clipStartInside, visible = segments.length;
+          if (inside || visible) {
+            listener.polygonStart();
+            if (inside) {
+              listener.lineStart();
+              interpolate(null, null, 1, listener);
+              listener.lineEnd();
+            }
+            if (visible) {
+              d3_geo_clipPolygon(segments, compare, clipStartInside, interpolate, listener);
+            }
+            listener.polygonEnd();
+          }
+          segments = polygon = ring = null;
+        }
+      };
+      function insidePolygon(p) {
+        var wn = 0, n = polygon.length, y = p[1];
+        for (var i = 0; i < n; ++i) {
+          for (var j = 1, v = polygon[i], m = v.length, a = v[0], b; j < m; ++j) {
+            b = v[j];
+            if (a[1] <= y) {
+              if (b[1] > y && d3_cross2d(a, b, p) > 0) ++wn;
+            } else {
+              if (b[1] <= y && d3_cross2d(a, b, p) < 0) --wn;
+            }
+            a = b;
+          }
+        }
+        return wn !== 0;
+      }
+      function interpolate(from, to, direction, listener) {
+        var a = 0, a1 = 0;
+        if (from == null || (a = corner(from, direction)) !== (a1 = corner(to, direction)) || comparePoints(from, to) < 0 ^ direction > 0) {
+          do {
+            listener.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0);
+          } while ((a = (a + direction + 4) % 4) !== a1);
+        } else {
+          listener.point(to[0], to[1]);
+        }
+      }
+      function pointVisible(x, y) {
+        return x0 <= x && x <= x1 && y0 <= y && y <= y1;
+      }
+      function point(x, y) {
+        if (pointVisible(x, y)) listener.point(x, y);
+      }
+      var x__, y__, v__, x_, y_, v_, first, clean;
+      function lineStart() {
+        clip.point = linePoint;
+        if (polygon) polygon.push(ring = []);
+        first = true;
+        v_ = false;
+        x_ = y_ = NaN;
+      }
+      function lineEnd() {
+        if (segments) {
+          linePoint(x__, y__);
+          if (v__ && v_) bufferListener.rejoin();
+          segments.push(bufferListener.buffer());
+        }
+        clip.point = point;
+        if (v_) listener.lineEnd();
+      }
+      function linePoint(x, y) {
+        x = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, x));
+        y = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, y));
+        var v = pointVisible(x, y);
+        if (polygon) ring.push([ x, y ]);
+        if (first) {
+          x__ = x, y__ = y, v__ = v;
+          first = false;
+          if (v) {
+            listener.lineStart();
+            listener.point(x, y);
+          }
+        } else {
+          if (v && v_) listener.point(x, y); else {
+            var l = {
+              a: {
+                x: x_,
+                y: y_
+              },
+              b: {
+                x: x,
+                y: y
+              }
+            };
+            if (clipLine(l)) {
+              if (!v_) {
+                listener.lineStart();
+                listener.point(l.a.x, l.a.y);
+              }
+              listener.point(l.b.x, l.b.y);
+              if (!v) listener.lineEnd();
+              clean = false;
+            } else if (v) {
+              listener.lineStart();
+              listener.point(x, y);
+              clean = false;
+            }
+          }
+        }
+        x_ = x, y_ = y, v_ = v;
+      }
+      return clip;
+    };
+    function corner(p, direction) {
+      return abs(p[0] - x0) < ε ? direction > 0 ? 0 : 3 : abs(p[0] - x1) < ε ? direction > 0 ? 2 : 1 : abs(p[1] - y0) < ε ? direction > 0 ? 1 : 0 : direction > 0 ? 3 : 2;
+    }
+    function compare(a, b) {
+      return comparePoints(a.x, b.x);
+    }
+    function comparePoints(a, b) {
+      var ca = corner(a, 1), cb = corner(b, 1);
+      return ca !== cb ? ca - cb : ca === 0 ? b[1] - a[1] : ca === 1 ? a[0] - b[0] : ca === 2 ? a[1] - b[1] : b[0] - a[0];
+    }
+  }
+  function d3_geo_compose(a, b) {
+    function compose(x, y) {
+      return x = a(x, y), b(x[0], x[1]);
+    }
+    if (a.invert && b.invert) compose.invert = function(x, y) {
+      return x = b.invert(x, y), x && a.invert(x[0], x[1]);
+    };
+    return compose;
+  }
+  function d3_geo_conic(projectAt) {
+    var φ0 = 0, φ1 = π / 3, m = d3_geo_projectionMutator(projectAt), p = m(φ0, φ1);
+    p.parallels = function(_) {
+      if (!arguments.length) return [ φ0 / π * 180, φ1 / π * 180 ];
+      return m(φ0 = _[0] * π / 180, φ1 = _[1] * π / 180);
+    };
+    return p;
+  }
+  function d3_geo_conicEqualArea(φ0, φ1) {
+    var sinφ0 = Math.sin(φ0), n = (sinφ0 + Math.sin(φ1)) / 2, C = 1 + sinφ0 * (2 * n - sinφ0), ρ0 = Math.sqrt(C) / n;
+    function forward(λ, φ) {
+      var ρ = Math.sqrt(C - 2 * n * Math.sin(φ)) / n;
+      return [ ρ * Math.sin(λ *= n), ρ0 - ρ * Math.cos(λ) ];
+    }
+    forward.invert = function(x, y) {
+      var ρ0_y = ρ0 - y;
+      return [ Math.atan2(x, ρ0_y) / n, d3_asin((C - (x * x + ρ0_y * ρ0_y) * n * n) / (2 * n)) ];
+    };
+    return forward;
+  }
+  (d3.geo.conicEqualArea = function() {
+    return d3_geo_conic(d3_geo_conicEqualArea);
+  }).raw = d3_geo_conicEqualArea;
+  d3.geo.albers = function() {
+    return d3.geo.conicEqualArea().rotate([ 96, 0 ]).center([ -.6, 38.7 ]).parallels([ 29.5, 45.5 ]).scale(1070);
+  };
+  d3.geo.albersUsa = function() {
+    var lower48 = d3.geo.albers();
+    var alaska = d3.geo.conicEqualArea().rotate([ 154, 0 ]).center([ -2, 58.5 ]).parallels([ 55, 65 ]);
+    var hawaii = d3.geo.conicEqualArea().rotate([ 157, 0 ]).center([ -3, 19.9 ]).parallels([ 8, 18 ]);
+    var point, pointStream = {
+      point: function(x, y) {
+        point = [ x, y ];
+      }
+    }, lower48Point, alaskaPoint, hawaiiPoint;
+    function albersUsa(coordinates) {
+      var x = coordinates[0], y = coordinates[1];
+      point = null;
+      (lower48Point(x, y), point) || (alaskaPoint(x, y), point) || hawaiiPoint(x, y);
+      return point;
+    }
+    albersUsa.invert = function(coordinates) {
+      var k = lower48.scale(), t = lower48.translate(), x = (coordinates[0] - t[0]) / k, y = (coordinates[1] - t[1]) / k;
+      return (y >= .12 && y < .234 && x >= -.425 && x < -.214 ? alaska : y >= .166 && y < .234 && x >= -.214 && x < -.115 ? hawaii : lower48).invert(coordinates);
+    };
+    albersUsa.stream = function(stream) {
+      var lower48Stream = lower48.stream(stream), alaskaStream = alaska.stream(stream), hawaiiStream = hawaii.stream(stream);
+      return {
+        point: function(x, y) {
+          lower48Stream.point(x, y);
+          alaskaStream.point(x, y);
+          hawaiiStream.point(x, y);
+        },
+        sphere: function() {
+          lower48Stream.sphere();
+          alaskaStream.sphere();
+          hawaiiStream.sphere();
+        },
+        lineStart: function() {
+          lower48Stream.lineStart();
+          alaskaStream.lineStart();
+          hawaiiStream.lineStart();
+        },
+        lineEnd: function() {
+          lower48Stream.lineEnd();
+          alaskaStream.lineEnd();
+          hawaiiStream.lineEnd();
+        },
+        polygonStart: function() {
+          lower48Stream.polygonStart();
+          alaskaStream.polygonStart();
+          hawaiiStream.polygonStart();
+        },
+        polygonEnd: function() {
+          lower48Stream.polygonEnd();
+          alaskaStream.polygonEnd();
+          hawaiiStream.polygonEnd();
+        }
+      };
+    };
+    albersUsa.precision = function(_) {
+      if (!arguments.length) return lower48.precision();
+      lower48.precision(_);
+      alaska.precision(_);
+      hawaii.precision(_);
+      return albersUsa;
+    };
+    albersUsa.scale = function(_) {
+      if (!arguments.length) return lower48.scale();
+      lower48.scale(_);
+      alaska.scale(_ * .35);
+      hawaii.scale(_);
+      return albersUsa.translate(lower48.translate());
+    };
+    albersUsa.translate = function(_) {
+      if (!arguments.length) return lower48.translate();
+      var k = lower48.scale(), x = +_[0], y = +_[1];
+      lower48Point = lower48.translate(_).clipExtent([ [ x - .455 * k, y - .238 * k ], [ x + .455 * k, y + .238 * k ] ]).stream(pointStream).point;
+      alaskaPoint = alaska.translate([ x - .307 * k, y + .201 * k ]).clipExtent([ [ x - .425 * k + ε, y + .12 * k + ε ], [ x - .214 * k - ε, y + .234 * k - ε ] ]).stream(pointStream).point;
+      hawaiiPoint = hawaii.translate([ x - .205 * k, y + .212 * k ]).clipExtent([ [ x - .214 * k + ε, y + .166 * k + ε ], [ x - .115 * k - ε, y + .234 * k - ε ] ]).stream(pointStream).point;
+      return albersUsa;
+    };
+    return albersUsa.scale(1070);
+  };
+  var d3_geo_pathAreaSum, d3_geo_pathAreaPolygon, d3_geo_pathArea = {
+    point: d3_noop,
+    lineStart: d3_noop,
+    lineEnd: d3_noop,
+    polygonStart: function() {
+      d3_geo_pathAreaPolygon = 0;
+      d3_geo_pathArea.lineStart = d3_geo_pathAreaRingStart;
+    },
+    polygonEnd: function() {
+      d3_geo_pathArea.lineStart = d3_geo_pathArea.lineEnd = d3_geo_pathArea.point = d3_noop;
+      d3_geo_pathAreaSum += abs(d3_geo_pathAreaPolygon / 2);
+    }
+  };
+  function d3_geo_pathAreaRingStart() {
+    var x00, y00, x0, y0;
+    d3_geo_pathArea.point = function(x, y) {
+      d3_geo_pathArea.point = nextPoint;
+      x00 = x0 = x, y00 = y0 = y;
+    };
+    function nextPoint(x, y) {
+      d3_geo_pathAreaPolygon += y0 * x - x0 * y;
+      x0 = x, y0 = y;
+    }
+    d3_geo_pathArea.lineEnd = function() {
+      nextPoint(x00, y00);
+    };
+  }
+  var d3_geo_pathBoundsX0, d3_geo_pathBoundsY0, d3_geo_pathBoundsX1, d3_geo_pathBoundsY1;
+  var d3_geo_pathBounds = {
+    point: d3_geo_pathBoundsPoint,
+    lineStart: d3_noop,
+    lineEnd: d3_noop,
+    polygonStart: d3_noop,
+    polygonEnd: d3_noop
+  };
+  function d3_geo_pathBoundsPoint(x, y) {
+    if (x < d3_geo_pathBoundsX0) d3_geo_pathBoundsX0 = x;
+    if (x > d3_geo_pathBoundsX1) d3_geo_pathBoundsX1 = x;
+    if (y < d3_geo_pathBoundsY0) d3_geo_pathBoundsY0 = y;
+    if (y > d3_geo_pathBoundsY1) d3_geo_pathBoundsY1 = y;
+  }
+  function d3_geo_pathBuffer() {
+    var pointCircle = d3_geo_pathBufferCircle(4.5), buffer = [];
+    var stream = {
+      point: point,
+      lineStart: function() {
+        stream.point = pointLineStart;
+      },
+      lineEnd: lineEnd,
+      polygonStart: function() {
+        stream.lineEnd = lineEndPolygon;
+      },
+      polygonEnd: function() {
+        stream.lineEnd = lineEnd;
+        stream.point = point;
+      },
+      pointRadius: function(_) {
+        pointCircle = d3_geo_pathBufferCircle(_);
+        return stream;
+      },
+      result: function() {
+        if (buffer.length) {
+          var result = buffer.join("");
+          buffer = [];
+          return result;
+        }
+      }
+    };
+    function point(x, y) {
+      buffer.push("M", x, ",", y, pointCircle);
+    }
+    function pointLineStart(x, y) {
+      buffer.push("M", x, ",", y);
+      stream.point = pointLine;
+    }
+    function pointLine(x, y) {
+      buffer.push("L", x, ",", y);
+    }
+    function lineEnd() {
+      stream.point = point;
+    }
+    function lineEndPolygon() {
+      buffer.push("Z");
+    }
+    return stream;
+  }
+  function d3_geo_pathBufferCircle(radius) {
+    return "m0," + radius + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius + "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius + "z";
+  }
+  var d3_geo_pathCentroid = {
+    point: d3_geo_pathCentroidPoint,
+    lineStart: d3_geo_pathCentroidLineStart,
+    lineEnd: d3_geo_pathCentroidLineEnd,
+    polygonStart: function() {
+      d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidRingStart;
+    },
+    polygonEnd: function() {
+      d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint;
+      d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidLineStart;
+      d3_geo_pathCentroid.lineEnd = d3_geo_pathCentroidLineEnd;
+    }
+  };
+  function d3_geo_pathCentroidPoint(x, y) {
+    d3_geo_centroidX0 += x;
+    d3_geo_centroidY0 += y;
+    ++d3_geo_centroidZ0;
+  }
+  function d3_geo_pathCentroidLineStart() {
+    var x0, y0;
+    d3_geo_pathCentroid.point = function(x, y) {
+      d3_geo_pathCentroid.point = nextPoint;
+      d3_geo_pathCentroidPoint(x0 = x, y0 = y);
+    };
+    function nextPoint(x, y) {
+      var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy);
+      d3_geo_centroidX1 += z * (x0 + x) / 2;
+      d3_geo_centroidY1 += z * (y0 + y) / 2;
+      d3_geo_centroidZ1 += z;
+      d3_geo_pathCentroidPoint(x0 = x, y0 = y);
+    }
+  }
+  function d3_geo_pathCentroidLineEnd() {
+    d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint;
+  }
+  function d3_geo_pathCentroidRingStart() {
+    var x00, y00, x0, y0;
+    d3_geo_pathCentroid.point = function(x, y) {
+      d3_geo_pathCentroid.point = nextPoint;
+      d3_geo_pathCentroidPoint(x00 = x0 = x, y00 = y0 = y);
+    };
+    function nextPoint(x, y) {
+      var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy);
+      d3_geo_centroidX1 += z * (x0 + x) / 2;
+      d3_geo_centroidY1 += z * (y0 + y) / 2;
+      d3_geo_centroidZ1 += z;
+      z = y0 * x - x0 * y;
+      d3_geo_centroidX2 += z * (x0 + x);
+      d3_geo_centroidY2 += z * (y0 + y);
+      d3_geo_centroidZ2 += z * 3;
+      d3_geo_pathCentroidPoint(x0 = x, y0 = y);
+    }
+    d3_geo_pathCentroid.lineEnd = function() {
+      nextPoint(x00, y00);
+    };
+  }
+  function d3_geo_pathContext(context) {
+    var pointRadius = 4.5;
+    var stream = {
+      point: point,
+      lineStart: function() {
+        stream.point = pointLineStart;
+      },
+      lineEnd: lineEnd,
+      polygonStart: function() {
+        stream.lineEnd = lineEndPolygon;
+      },
+      polygonEnd: function() {
+        stream.lineEnd = lineEnd;
+        stream.point = point;
+      },
+      pointRadius: function(_) {
+        pointRadius = _;
+        return stream;
+      },
+      result: d3_noop
+    };
+    function point(x, y) {
+      context.moveTo(x, y);
+      context.arc(x, y, pointRadius, 0, τ);
+    }
+    function pointLineStart(x, y) {
+      context.moveTo(x, y);
+      stream.point = pointLine;
+    }
+    function pointLine(x, y) {
+      context.lineTo(x, y);
+    }
+    function lineEnd() {
+      stream.point = point;
+    }
+    function lineEndPolygon() {
+      context.closePath();
+    }
+    return stream;
+  }
+  function d3_geo_resample(project) {
+    var δ2 = .5, cosMinDistance = Math.cos(30 * d3_radians), maxDepth = 16;
+    function resample(stream) {
+      return (maxDepth ? resampleRecursive : resampleNone)(stream);
+    }
+    function resampleNone(stream) {
+      return d3_geo_transformPoint(stream, function(x, y) {
+        x = project(x, y);
+        stream.point(x[0], x[1]);
+      });
+    }
+    function resampleRecursive(stream) {
+      var λ00, φ00, x00, y00, a00, b00, c00, λ0, x0, y0, a0, b0, c0;
+      var resample = {
+        point: point,
+        lineStart: lineStart,
+        lineEnd: lineEnd,
+        polygonStart: function() {
+          stream.polygonStart();
+          resample.lineStart = ringStart;
+        },
+        polygonEnd: function() {
+          stream.polygonEnd();
+          resample.lineStart = lineStart;
+        }
+      };
+      function point(x, y) {
+        x = project(x, y);
+        stream.point(x[0], x[1]);
+      }
+      function lineStart() {
+        x0 = NaN;
+        resample.point = linePoint;
+        stream.lineStart();
+      }
+      function linePoint(λ, φ) {
+        var c = d3_geo_cartesian([ λ, φ ]), p = project(λ, φ);
+        resampleLineTo(x0, y0, λ0, a0, b0, c0, x0 = p[0], y0 = p[1], λ0 = λ, a0 = c[0], b0 = c[1], c0 = c[2], maxDepth, stream);
+        stream.point(x0, y0);
+      }
+      function lineEnd() {
+        resample.point = point;
+        stream.lineEnd();
+      }
+      function ringStart() {
+        lineStart();
+        resample.point = ringPoint;
+        resample.lineEnd = ringEnd;
+      }
+      function ringPoint(λ, φ) {
+        linePoint(λ00 = λ, φ00 = φ), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0;
+        resample.point = linePoint;
+      }
+      function ringEnd() {
+        resampleLineTo(x0, y0, λ0, a0, b0, c0, x00, y00, λ00, a00, b00, c00, maxDepth, stream);
+        resample.lineEnd = lineEnd;
+        lineEnd();
+      }
+      return resample;
+    }
+    function resampleLineTo(x0, y0, λ0, a0, b0, c0, x1, y1, λ1, a1, b1, c1, depth, stream) {
+      var dx = x1 - x0, dy = y1 - y0, d2 = dx * dx + dy * dy;
+      if (d2 > 4 * δ2 && depth--) {
+        var a = a0 + a1, b = b0 + b1, c = c0 + c1, m = Math.sqrt(a * a + b * b + c * c), φ2 = Math.asin(c /= m), λ2 = abs(abs(c) - 1) < ε || abs(λ0 - λ1) < ε ? (λ0 + λ1) / 2 : Math.atan2(b, a), p = project(λ2, φ2), x2 = p[0], y2 = p[1], dx2 = x2 - x0, dy2 = y2 - y0, dz = dy * dx2 - dx * dy2;
+        if (dz * dz / d2 > δ2 || abs((dx * dx2 + dy * dy2) / d2 - .5) > .3 || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) {
+          resampleLineTo(x0, y0, λ0, a0, b0, c0, x2, y2, λ2, a /= m, b /= m, c, depth, stream);
+          stream.point(x2, y2);
+          resampleLineTo(x2, y2, λ2, a, b, c, x1, y1, λ1, a1, b1, c1, depth, stream);
+        }
+      }
+    }
+    resample.precision = function(_) {
+      if (!arguments.length) return Math.sqrt(δ2);
+      maxDepth = (δ2 = _ * _) > 0 && 16;
+      return resample;
+    };
+    return resample;
+  }
+  d3.geo.path = function() {
+    var pointRadius = 4.5, projection, context, projectStream, contextStream, cacheStream;
+    function path(object) {
+      if (object) {
+        if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments));
+        if (!cacheStream || !cacheStream.valid) cacheStream = projectStream(contextStream);
+        d3.geo.stream(object, cacheStream);
+      }
+      return contextStream.result();
+    }
+    path.area = function(object) {
+      d3_geo_pathAreaSum = 0;
+      d3.geo.stream(object, projectStream(d3_geo_pathArea));
+      return d3_geo_pathAreaSum;
+    };
+    path.centroid = function(object) {
+      d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 = d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 = d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0;
+      d3.geo.stream(object, projectStream(d3_geo_pathCentroid));
+      return d3_geo_centroidZ2 ? [ d3_geo_centroidX2 / d3_geo_centroidZ2, d3_geo_centroidY2 / d3_geo_centroidZ2 ] : d3_geo_centroidZ1 ? [ d3_geo_centroidX1 / d3_geo_centroidZ1, d3_geo_centroidY1 / d3_geo_centroidZ1 ] : d3_geo_centroidZ0 ? [ d3_geo_centroidX0 / d3_geo_centroidZ0, d3_geo_centroidY0 / d3_geo_centroidZ0 ] : [ NaN, NaN ];
+    };
+    path.bounds = function(object) {
+      d3_geo_pathBoundsX1 = d3_geo_pathBoundsY1 = -(d3_geo_pathBoundsX0 = d3_geo_pathBoundsY0 = Infinity);
+      d3.geo.stream(object, projectStream(d3_geo_pathBounds));
+      return [ [ d3_geo_pathBoundsX0, d3_geo_pathBoundsY0 ], [ d3_geo_pathBoundsX1, d3_geo_pathBoundsY1 ] ];
+    };
+    path.projection = function(_) {
+      if (!arguments.length) return projection;
+      projectStream = (projection = _) ? _.stream || d3_geo_pathProjectStream(_) : d3_identity;
+      return reset();
+    };
+    path.context = function(_) {
+      if (!arguments.length) return context;
+      contextStream = (context = _) == null ? new d3_geo_pathBuffer() : new d3_geo_pathContext(_);
+      if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius);
+      return reset();
+    };
+    path.pointRadius = function(_) {
+      if (!arguments.length) return pointRadius;
+      pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_);
+      return path;
+    };
+    function reset() {
+      cacheStream = null;
+      return path;
+    }
+    return path.projection(d3.geo.albersUsa()).context(null);
+  };
+  function d3_geo_pathProjectStream(project) {
+    var resample = d3_geo_resample(function(x, y) {
+      return project([ x * d3_degrees, y * d3_degrees ]);
+    });
+    return function(stream) {
+      return d3_geo_projectionRadians(resample(stream));
+    };
+  }
+  d3.geo.transform = function(methods) {
+    return {
+      stream: function(stream) {
+        var transform = new d3_geo_transform(stream);
+        for (var k in methods) transform[k] = methods[k];
+        return transform;
+      }
+    };
+  };
+  function d3_geo_transform(stream) {
+    this.stream = stream;
+  }
+  d3_geo_transform.prototype = {
+    point: function(x, y) {
+      this.stream.point(x, y);
+    },
+    sphere: function() {
+      this.stream.sphere();
+    },
+    lineStart: function() {
+      this.stream.lineStart();
+    },
+    lineEnd: function() {
+      this.stream.lineEnd();
+    },
+    polygonStart: function() {
+      this.stream.polygonStart();
+    },
+    polygonEnd: function() {
+      this.stream.polygonEnd();
+    }
+  };
+  function d3_geo_transformPoint(stream, point) {
+    return {
+      point: point,
+      sphere: function() {
+        stream.sphere();
+      },
+      lineStart: function() {
+        stream.lineStart();
+      },
+      lineEnd: function() {
+        stream.lineEnd();
+      },
+      polygonStart: function() {
+        stream.polygonStart();
+      },
+      polygonEnd: function() {
+        stream.polygonEnd();
+      }
+    };
+  }
+  d3.geo.projection = d3_geo_projection;
+  d3.geo.projectionMutator = d3_geo_projectionMutator;
+  function d3_geo_projection(project) {
+    return d3_geo_projectionMutator(function() {
+      return project;
+    })();
+  }
+  function d3_geo_projectionMutator(projectAt) {
+    var project, rotate, projectRotate, projectResample = d3_geo_resample(function(x, y) {
+      x = project(x, y);
+      return [ x[0] * k + δx, δy - x[1] * k ];
+    }), k = 150, x = 480, y = 250, λ = 0, φ = 0, δλ = 0, δφ = 0, δγ = 0, δx, δy, preclip = d3_geo_clipAntimeridian, postclip = d3_identity, clipAngle = null, clipExtent = null, stream;
+    function projection(point) {
+      point = projectRotate(point[0] * d3_radians, point[1] * d3_radians);
+      return [ point[0] * k + δx, δy - point[1] * k ];
+    }
+    function invert(point) {
+      point = projectRotate.invert((point[0] - δx) / k, (δy - point[1]) / k);
+      return point && [ point[0] * d3_degrees, point[1] * d3_degrees ];
+    }
+    projection.stream = function(output) {
+      if (stream) stream.valid = false;
+      stream = d3_geo_projectionRadians(preclip(rotate, projectResample(postclip(output))));
+      stream.valid = true;
+      return stream;
+    };
+    projection.clipAngle = function(_) {
+      if (!arguments.length) return clipAngle;
+      preclip = _ == null ? (clipAngle = _, d3_geo_clipAntimeridian) : d3_geo_clipCircle((clipAngle = +_) * d3_radians);
+      return invalidate();
+    };
+    projection.clipExtent = function(_) {
+      if (!arguments.length) return clipExtent;
+      clipExtent = _;
+      postclip = _ ? d3_geo_clipExtent(_[0][0], _[0][1], _[1][0], _[1][1]) : d3_identity;
+      return invalidate();
+    };
+    projection.scale = function(_) {
+      if (!arguments.length) return k;
+      k = +_;
+      return reset();
+    };
+    projection.translate = function(_) {
+      if (!arguments.length) return [ x, y ];
+      x = +_[0];
+      y = +_[1];
+      return reset();
+    };
+    projection.center = function(_) {
+      if (!arguments.length) return [ λ * d3_degrees, φ * d3_degrees ];
+      λ = _[0] % 360 * d3_radians;
+      φ = _[1] % 360 * d3_radians;
+      return reset();
+    };
+    projection.rotate = function(_) {
+      if (!arguments.length) return [ δλ * d3_degrees, δφ * d3_degrees, δγ * d3_degrees ];
+      δλ = _[0] % 360 * d3_radians;
+      δφ = _[1] % 360 * d3_radians;
+      δγ = _.length > 2 ? _[2] % 360 * d3_radians : 0;
+      return reset();
+    };
+    d3.rebind(projection, projectResample, "precision");
+    function reset() {
+      projectRotate = d3_geo_compose(rotate = d3_geo_rotation(δλ, δφ, δγ), project);
+      var center = project(λ, φ);
+      δx = x - center[0] * k;
+      δy = y + center[1] * k;
+      return invalidate();
+    }
+    function invalidate() {
+      if (stream) stream.valid = false, stream = null;
+      return projection;
+    }
+    return function() {
+      project = projectAt.apply(this, arguments);
+      projection.invert = project.invert && invert;
+      return reset();
+    };
+  }
+  function d3_geo_projectionRadians(stream) {
+    return d3_geo_transformPoint(stream, function(x, y) {
+      stream.point(x * d3_radians, y * d3_radians);
+    });
+  }
+  function d3_geo_equirectangular(λ, φ) {
+    return [ λ, φ ];
+  }
+  (d3.geo.equirectangular = function() {
+    return d3_geo_projection(d3_geo_equirectangular);
+  }).raw = d3_geo_equirectangular.invert = d3_geo_equirectangular;
+  d3.geo.rotation = function(rotate) {
+    rotate = d3_geo_rotation(rotate[0] % 360 * d3_radians, rotate[1] * d3_radians, rotate.length > 2 ? rotate[2] * d3_radians : 0);
+    function forward(coordinates) {
+      coordinates = rotate(coordinates[0] * d3_radians, coordinates[1] * d3_radians);
+      return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates;
+    }
+    forward.invert = function(coordinates) {
+      coordinates = rotate.invert(coordinates[0] * d3_radians, coordinates[1] * d3_radians);
+      return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates;
+    };
+    return forward;
+  };
+  function d3_geo_identityRotation(λ, φ) {
+    return [ λ > π ? λ - τ : λ < -π ? λ + τ : λ, φ ];
+  }
+  d3_geo_identityRotation.invert = d3_geo_equirectangular;
+  function d3_geo_rotation(δλ, δφ, δγ) {
+    return δλ ? δφ || δγ ? d3_geo_compose(d3_geo_rotationλ(δλ), d3_geo_rotationφγ(δφ, δγ)) : d3_geo_rotationλ(δλ) : δφ || δγ ? d3_geo_rotationφγ(δφ, δγ) : d3_geo_identityRotation;
+  }
+  function d3_geo_forwardRotationλ(δλ) {
+    return function(λ, φ) {
+      return λ += δλ, [ λ > π ? λ - τ : λ < -π ? λ + τ : λ, φ ];
+    };
+  }
+  function d3_geo_rotationλ(δλ) {
+    var rotation = d3_geo_forwardRotationλ(δλ);
+    rotation.invert = d3_geo_forwardRotationλ(-δλ);
+    return rotation;
+  }
+  function d3_geo_rotationφγ(δφ, δγ) {
+    var cosδφ = Math.cos(δφ), sinδφ = Math.sin(δφ), cosδγ = Math.cos(δγ), sinδγ = Math.sin(δγ);
+    function rotation(λ, φ) {
+      var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδφ + x * sinδφ;
+      return [ Math.atan2(y * cosδγ - k * sinδγ, x * cosδφ - z * sinδφ), d3_asin(k * cosδγ + y * sinδγ) ];
+    }
+    rotation.invert = function(λ, φ) {
+      var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδγ - y * sinδγ;
+      return [ Math.atan2(y * cosδγ + z * sinδγ, x * cosδφ + k * sinδφ), d3_asin(k * cosδφ - x * sinδφ) ];
+    };
+    return rotation;
+  }
+  d3.geo.circle = function() {
+    var origin = [ 0, 0 ], angle, precision = 6, interpolate;
+    function circle() {
+      var center = typeof origin === "function" ? origin.apply(this, arguments) : origin, rotate = d3_geo_rotation(-center[0] * d3_radians, -center[1] * d3_radians, 0).invert, ring = [];
+      interpolate(null, null, 1, {
+        point: function(x, y) {
+          ring.push(x = rotate(x, y));
+          x[0] *= d3_degrees, x[1] *= d3_degrees;
+        }
+      });
+      return {
+        type: "Polygon",
+        coordinates: [ ring ]
+      };
+    }
+    circle.origin = function(x) {
+      if (!arguments.length) return origin;
+      origin = x;
+      return circle;
+    };
+    circle.angle = function(x) {
+      if (!arguments.length) return angle;
+      interpolate = d3_geo_circleInterpolate((angle = +x) * d3_radians, precision * d3_radians);
+      return circle;
+    };
+    circle.precision = function(_) {
+      if (!arguments.length) return precision;
+      interpolate = d3_geo_circleInterpolate(angle * d3_radians, (precision = +_) * d3_radians);
+      return circle;
+    };
+    return circle.angle(90);
+  };
+  function d3_geo_circleInterpolate(radius, precision) {
+    var cr = Math.cos(radius), sr = Math.sin(radius);
+    return function(from, to, direction, listener) {
+      var step = direction * precision;
+      if (from != null) {
+        from = d3_geo_circleAngle(cr, from);
+        to = d3_geo_circleAngle(cr, to);
+        if (direction > 0 ? from < to : from > to) from += direction * τ;
+      } else {
+        from = radius + direction * τ;
+        to = radius - .5 * step;
+      }
+      for (var point, t = from; direction > 0 ? t > to : t < to; t -= step) {
+        listener.point((point = d3_geo_spherical([ cr, -sr * Math.cos(t), -sr * Math.sin(t) ]))[0], point[1]);
+      }
+    };
+  }
+  function d3_geo_circleAngle(cr, point) {
+    var a = d3_geo_cartesian(point);
+    a[0] -= cr;
+    d3_geo_cartesianNormalize(a);
+    var angle = d3_acos(-a[1]);
+    return ((-a[2] < 0 ? -angle : angle) + 2 * Math.PI - ε) % (2 * Math.PI);
+  }
+  d3.geo.distance = function(a, b) {
+    var Δλ = (b[0] - a[0]) * d3_radians, φ0 = a[1] * d3_radians, φ1 = b[1] * d3_radians, sinΔλ = Math.sin(Δλ), cosΔλ = Math.cos(Δλ), sinφ0 = Math.sin(φ0), cosφ0 = Math.cos(φ0), sinφ1 = Math.sin(φ1), cosφ1 = Math.cos(φ1), t;
+    return Math.atan2(Math.sqrt((t = cosφ1 * sinΔλ) * t + (t = cosφ0 * sinφ1 - sinφ0 * cosφ1 * cosΔλ) * t), sinφ0 * sinφ1 + cosφ0 * cosφ1 * cosΔλ);
+  };
+  d3.geo.graticule = function() {
+    var x1, x0, X1, X0, y1, y0, Y1, Y0, dx = 10, dy = dx, DX = 90, DY = 360, x, y, X, Y, precision = 2.5;
+    function graticule() {
+      return {
+        type: "MultiLineString",
+        coordinates: lines()
+      };
+    }
+    function lines() {
+      return d3.range(Math.ceil(X0 / DX) * DX, X1, DX).map(X).concat(d3.range(Math.ceil(Y0 / DY) * DY, Y1, DY).map(Y)).concat(d3.range(Math.ceil(x0 / dx) * dx, x1, dx).filter(function(x) {
+        return abs(x % DX) > ε;
+      }).map(x)).concat(d3.range(Math.ceil(y0 / dy) * dy, y1, dy).filter(function(y) {
+        return abs(y % DY) > ε;
+      }).map(y));
+    }
+    graticule.lines = function() {
+      return lines().map(function(coordinates) {
+        return {
+          type: "LineString",
+          coordinates: coordinates
+        };
+      });
+    };
+    graticule.outline = function() {
+      return {
+        type: "Polygon",
+        coordinates: [ X(X0).concat(Y(Y1).slice(1), X(X1).reverse().slice(1), Y(Y0).reverse().slice(1)) ]
+      };
+    };
+    graticule.extent = function(_) {
+      if (!arguments.length) return graticule.minorExtent();
+      return graticule.majorExtent(_).minorExtent(_);
+    };
+    graticule.majorExtent = function(_) {
+      if (!arguments.length) return [ [ X0, Y0 ], [ X1, Y1 ] ];
+      X0 = +_[0][0], X1 = +_[1][0];
+      Y0 = +_[0][1], Y1 = +_[1][1];
+      if (X0 > X1) _ = X0, X0 = X1, X1 = _;
+      if (Y0 > Y1) _ = Y0, Y0 = Y1, Y1 = _;
+      return graticule.precision(precision);
+    };
+    graticule.minorExtent = function(_) {
+      if (!arguments.length) return [ [ x0, y0 ], [ x1, y1 ] ];
+      x0 = +_[0][0], x1 = +_[1][0];
+      y0 = +_[0][1], y1 = +_[1][1];
+      if (x0 > x1) _ = x0, x0 = x1, x1 = _;
+      if (y0 > y1) _ = y0, y0 = y1, y1 = _;
+      return graticule.precision(precision);
+    };
+    graticule.step = function(_) {
+      if (!arguments.length) return graticule.minorStep();
+      return graticule.majorStep(_).minorStep(_);
+    };
+    graticule.majorStep = function(_) {
+      if (!arguments.length) return [ DX, DY ];
+      DX = +_[0], DY = +_[1];
+      return graticule;
+    };
+    graticule.minorStep = function(_) {
+      if (!arguments.length) return [ dx, dy ];
+      dx = +_[0], dy = +_[1];
+      return graticule;
+    };
+    graticule.precision = function(_) {
+      if (!arguments.length) return precision;
+      precision = +_;
+      x = d3_geo_graticuleX(y0, y1, 90);
+      y = d3_geo_graticuleY(x0, x1, precision);
+      X = d3_geo_graticuleX(Y0, Y1, 90);
+      Y = d3_geo_graticuleY(X0, X1, precision);
+      return graticule;
+    };
+    return graticule.majorExtent([ [ -180, -90 + ε ], [ 180, 90 - ε ] ]).minorExtent([ [ -180, -80 - ε ], [ 180, 80 + ε ] ]);
+  };
+  function d3_geo_graticuleX(y0, y1, dy) {
+    var y = d3.range(y0, y1 - ε, dy).concat(y1);
+    return function(x) {
+      return y.map(function(y) {
+        return [ x, y ];
+      });
+    };
+  }
+  function d3_geo_graticuleY(x0, x1, dx) {
+    var x = d3.range(x0, x1 - ε, dx).concat(x1);
+    return function(y) {
+      return x.map(function(x) {
+        return [ x, y ];
+      });
+    };
+  }
+  function d3_source(d) {
+    return d.source;
+  }
+  function d3_target(d) {
+    return d.target;
+  }
+  d3.geo.greatArc = function() {
+    var source = d3_source, source_, target = d3_target, target_;
+    function greatArc() {
+      return {
+        type: "LineString",
+        coordinates: [ source_ || source.apply(this, arguments), target_ || target.apply(this, arguments) ]
+      };
+    }
+    greatArc.distance = function() {
+      return d3.geo.distance(source_ || source.apply(this, arguments), target_ || target.apply(this, arguments));
+    };
+    greatArc.source = function(_) {
+      if (!arguments.length) return source;
+      source = _, source_ = typeof _ === "function" ? null : _;
+      return greatArc;
+    };
+    greatArc.target = function(_) {
+      if (!arguments.length) return target;
+      target = _, target_ = typeof _ === "function" ? null : _;
+      return greatArc;
+    };
+    greatArc.precision = function() {
+      return arguments.length ? greatArc : 0;
+    };
+    return greatArc;
+  };
+  d3.geo.interpolate = function(source, target) {
+    return d3_geo_interpolate(source[0] * d3_radians, source[1] * d3_radians, target[0] * d3_radians, target[1] * d3_radians);
+  };
+  function d3_geo_interpolate(x0, y0, x1, y1) {
+    var cy0 = Math.cos(y0), sy0 = Math.sin(y0), cy1 = Math.cos(y1), sy1 = Math.sin(y1), kx0 = cy0 * Math.cos(x0), ky0 = cy0 * Math.sin(x0), kx1 = cy1 * Math.cos(x1), ky1 = cy1 * Math.sin(x1), d = 2 * Math.asin(Math.sqrt(d3_haversin(y1 - y0) + cy0 * cy1 * d3_haversin(x1 - x0))), k = 1 / Math.sin(d);
+    var interpolate = d ? function(t) {
+      var B = Math.sin(t *= d) * k, A = Math.sin(d - t) * k, x = A * kx0 + B * kx1, y = A * ky0 + B * ky1, z = A * sy0 + B * sy1;
+      return [ Math.atan2(y, x) * d3_degrees, Math.atan2(z, Math.sqrt(x * x + y * y)) * d3_degrees ];
+    } : function() {
+      return [ x0 * d3_degrees, y0 * d3_degrees ];
+    };
+    interpolate.distance = d;
+    return interpolate;
+  }
+  d3.geo.length = function(object) {
+    d3_geo_lengthSum = 0;
+    d3.geo.stream(object, d3_geo_length);
+    return d3_geo_lengthSum;
+  };
+  var d3_geo_lengthSum;
+  var d3_geo_length = {
+    sphere: d3_noop,
+    point: d3_noop,
+    lineStart: d3_geo_lengthLineStart,
+    lineEnd: d3_noop,
+    polygonStart: d3_noop,
+    polygonEnd: d3_noop
+  };
+  function d3_geo_lengthLineStart() {
+    var λ0, sinφ0, cosφ0;
+    d3_geo_length.point = function(λ, φ) {
+      λ0 = λ * d3_radians, sinφ0 = Math.sin(φ *= d3_radians), cosφ0 = Math.cos(φ);
+      d3_geo_length.point = nextPoint;
+    };
+    d3_geo_length.lineEnd = function() {
+      d3_geo_length.point = d3_geo_length.lineEnd = d3_noop;
+    };
+    function nextPoint(λ, φ) {
+      var sinφ = Math.sin(φ *= d3_radians), cosφ = Math.cos(φ), t = abs((λ *= d3_radians) - λ0), cosΔλ = Math.cos(t);
+      d3_geo_lengthSum += Math.atan2(Math.sqrt((t = cosφ * Math.sin(t)) * t + (t = cosφ0 * sinφ - sinφ0 * cosφ * cosΔλ) * t), sinφ0 * sinφ + cosφ0 * cosφ * cosΔλ);
+      λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ;
+    }
+  }
+  function d3_geo_azimuthal(scale, angle) {
+    function azimuthal(λ, φ) {
+      var cosλ = Math.cos(λ), cosφ = Math.cos(φ), k = scale(cosλ * cosφ);
+      return [ k * cosφ * Math.sin(λ), k * Math.sin(φ) ];
+    }
+    azimuthal.invert = function(x, y) {
+      var ρ = Math.sqrt(x * x + y * y), c = angle(ρ), sinc = Math.sin(c), cosc = Math.cos(c);
+      return [ Math.atan2(x * sinc, ρ * cosc), Math.asin(ρ && y * sinc / ρ) ];
+    };
+    return azimuthal;
+  }
+  var d3_geo_azimuthalEqualArea = d3_geo_azimuthal(function(cosλcosφ) {
+    return Math.sqrt(2 / (1 + cosλcosφ));
+  }, function(ρ) {
+    return 2 * Math.asin(ρ / 2);
+  });
+  (d3.geo.azimuthalEqualArea = function() {
+    return d3_geo_projection(d3_geo_azimuthalEqualArea);
+  }).raw = d3_geo_azimuthalEqualArea;
+  var d3_geo_azimuthalEquidistant = d3_geo_azimuthal(function(cosλcosφ) {
+    var c = Math.acos(cosλcosφ);
+    return c && c / Math.sin(c);
+  }, d3_identity);
+  (d3.geo.azimuthalEquidistant = function() {
+    return d3_geo_projection(d3_geo_azimuthalEquidistant);
+  }).raw = d3_geo_azimuthalEquidistant;
+  function d3_geo_conicConformal(φ0, φ1) {
+    var cosφ0 = Math.cos(φ0), t = function(φ) {
+      return Math.tan(π / 4 + φ / 2);
+    }, n = φ0 === φ1 ? Math.sin(φ0) : Math.log(cosφ0 / Math.cos(φ1)) / Math.log(t(φ1) / t(φ0)), F = cosφ0 * Math.pow(t(φ0), n) / n;
+    if (!n) return d3_geo_mercator;
+    function forward(λ, φ) {
+      if (F > 0) {
+        if (φ < -halfπ + ε) φ = -halfπ + ε;
+      } else {
+        if (φ > halfπ - ε) φ = halfπ - ε;
+      }
+      var ρ = F / Math.pow(t(φ), n);
+      return [ ρ * Math.sin(n * λ), F - ρ * Math.cos(n * λ) ];
+    }
+    forward.invert = function(x, y) {
+      var ρ0_y = F - y, ρ = d3_sgn(n) * Math.sqrt(x * x + ρ0_y * ρ0_y);
+      return [ Math.atan2(x, ρ0_y) / n, 2 * Math.atan(Math.pow(F / ρ, 1 / n)) - halfπ ];
+    };
+    return forward;
+  }
+  (d3.geo.conicConformal = function() {
+    return d3_geo_conic(d3_geo_conicConformal);
+  }).raw = d3_geo_conicConformal;
+  function d3_geo_conicEquidistant(φ0, φ1) {
+    var cosφ0 = Math.cos(φ0), n = φ0 === φ1 ? Math.sin(φ0) : (cosφ0 - Math.cos(φ1)) / (φ1 - φ0), G = cosφ0 / n + φ0;
+    if (abs(n) < ε) return d3_geo_equirectangular;
+    function forward(λ, φ) {
+      var ρ = G - φ;
+      return [ ρ * Math.sin(n * λ), G - ρ * Math.cos(n * λ) ];
+    }
+    forward.invert = function(x, y) {
+      var ρ0_y = G - y;
+      return [ Math.atan2(x, ρ0_y) / n, G - d3_sgn(n) * Math.sqrt(x * x + ρ0_y * ρ0_y) ];
+    };
+    return forward;
+  }
+  (d3.geo.conicEquidistant = function() {
+    return d3_geo_conic(d3_geo_conicEquidistant);
+  }).raw = d3_geo_conicEquidistant;
+  var d3_geo_gnomonic = d3_geo_azimuthal(function(cosλcosφ) {
+    return 1 / cosλcosφ;
+  }, Math.atan);
+  (d3.geo.gnomonic = function() {
+    return d3_geo_projection(d3_geo_gnomonic);
+  }).raw = d3_geo_gnomonic;
+  function d3_geo_mercator(λ, φ) {
+    return [ λ, Math.log(Math.tan(π / 4 + φ / 2)) ];
+  }
+  d3_geo_mercator.invert = function(x, y) {
+    return [ x, 2 * Math.atan(Math.exp(y)) - halfπ ];
+  };
+  function d3_geo_mercatorProjection(project) {
+    var m = d3_geo_projection(project), scale = m.scale, translate = m.translate, clipExtent = m.clipExtent, clipAuto;
+    m.scale = function() {
+      var v = scale.apply(m, arguments);
+      return v === m ? clipAuto ? m.clipExtent(null) : m : v;
+    };
+    m.translate = function() {
+      var v = translate.apply(m, arguments);
+      return v === m ? clipAuto ? m.clipExtent(null) : m : v;
+    };
+    m.clipExtent = function(_) {
+      var v = clipExtent.apply(m, arguments);
+      if (v === m) {
+        if (clipAuto = _ == null) {
+          var k = π * scale(), t = translate();
+          clipExtent([ [ t[0] - k, t[1] - k ], [ t[0] + k, t[1] + k ] ]);
+        }
+      } else if (clipAuto) {
+        v = null;
+      }
+      return v;
+    };
+    return m.clipExtent(null);
+  }
+  (d3.geo.mercator = function() {
+    return d3_geo_mercatorProjection(d3_geo_mercator);
+  }).raw = d3_geo_mercator;
+  var d3_geo_orthographic = d3_geo_azimuthal(function() {
+    return 1;
+  }, Math.asin);
+  (d3.geo.orthographic = function() {
+    return d3_geo_projection(d3_geo_orthographic);
+  }).raw = d3_geo_orthographic;
+  var d3_geo_stereographic = d3_geo_azimuthal(function(cosλcosφ) {
+    return 1 / (1 + cosλcosφ);
+  }, function(ρ) {
+    return 2 * Math.atan(ρ);
+  });
+  (d3.geo.stereographic = function() {
+    return d3_geo_projection(d3_geo_stereographic);
+  }).raw = d3_geo_stereographic;
+  function d3_geo_transverseMercator(λ, φ) {
+    return [ Math.log(Math.tan(π / 4 + φ / 2)), -λ ];
+  }
+  d3_geo_transverseMercator.invert = function(x, y) {
+    return [ -y, 2 * Math.atan(Math.exp(x)) - halfπ ];
+  };
+  (d3.geo.transverseMercator = function() {
+    var projection = d3_geo_mercatorProjection(d3_geo_transverseMercator), center = projection.center, rotate = projection.rotate;
+    projection.center = function(_) {
+      return _ ? center([ -_[1], _[0] ]) : (_ = center(), [ -_[1], _[0] ]);
+    };
+    projection.rotate = function(_) {
+      return _ ? rotate([ _[0], _[1], _.length > 2 ? _[2] + 90 : 90 ]) : (_ = rotate(), 
+      [ _[0], _[1], _[2] - 90 ]);
+    };
+    return projection.rotate([ 0, 0 ]);
+  }).raw = d3_geo_transverseMercator;
+  d3.geom = {};
+  function d3_geom_pointX(d) {
+    return d[0];
+  }
+  function d3_geom_pointY(d) {
+    return d[1];
+  }
+  d3.geom.hull = function(vertices) {
+    var x = d3_geom_pointX, y = d3_geom_pointY;
+    if (arguments.length) return hull(vertices);
+    function hull(data) {
+      if (data.length < 3) return [];
+      var fx = d3_functor(x), fy = d3_functor(y), i, n = data.length, points = [], flippedPoints = [];
+      for (i = 0; i < n; i++) {
+        points.push([ +fx.call(this, data[i], i), +fy.call(this, data[i], i), i ]);
+      }
+      points.sort(d3_geom_hullOrder);
+      for (i = 0; i < n; i++) flippedPoints.push([ points[i][0], -points[i][1] ]);
+      var upper = d3_geom_hullUpper(points), lower = d3_geom_hullUpper(flippedPoints);
+      var skipLeft = lower[0] === upper[0], skipRight = lower[lower.length - 1] === upper[upper.length - 1], polygon = [];
+      for (i = upper.length - 1; i >= 0; --i) polygon.push(data[points[upper[i]][2]]);
+      for (i = +skipLeft; i < lower.length - skipRight; ++i) polygon.push(data[points[lower[i]][2]]);
+      return polygon;
+    }
+    hull.x = function(_) {
+      return arguments.length ? (x = _, hull) : x;
+    };
+    hull.y = function(_) {
+      return arguments.length ? (y = _, hull) : y;
+    };
+    return hull;
+  };
+  function d3_geom_hullUpper(points) {
+    var n = points.length, hull = [ 0, 1 ], hs = 2;
+    for (var i = 2; i < n; i++) {
+      while (hs > 1 && d3_cross2d(points[hull[hs - 2]], points[hull[hs - 1]], points[i]) <= 0) --hs;
+      hull[hs++] = i;
+    }
+    return hull.slice(0, hs);
+  }
+  function d3_geom_hullOrder(a, b) {
+    return a[0] - b[0] || a[1] - b[1];
+  }
+  d3.geom.polygon = function(coordinates) {
+    d3_subclass(coordinates, d3_geom_polygonPrototype);
+    return coordinates;
+  };
+  var d3_geom_polygonPrototype = d3.geom.polygon.prototype = [];
+  d3_geom_polygonPrototype.area = function() {
+    var i = -1, n = this.length, a, b = this[n - 1], area = 0;
+    while (++i < n) {
+      a = b;
+      b = this[i];
+      area += a[1] * b[0] - a[0] * b[1];
+    }
+    return area * .5;
+  };
+  d3_geom_polygonPrototype.centroid = function(k) {
+    var i = -1, n = this.length, x = 0, y = 0, a, b = this[n - 1], c;
+    if (!arguments.length) k = -1 / (6 * this.area());
+    while (++i < n) {
+      a = b;
+      b = this[i];
+      c = a[0] * b[1] - b[0] * a[1];
+      x += (a[0] + b[0]) * c;
+      y += (a[1] + b[1]) * c;
+    }
+    return [ x * k, y * k ];
+  };
+  d3_geom_polygonPrototype.clip = function(subject) {
+    var input, closed = d3_geom_polygonClosed(subject), i = -1, n = this.length - d3_geom_polygonClosed(this), j, m, a = this[n - 1], b, c, d;
+    while (++i < n) {
+      input = subject.slice();
+      subject.length = 0;
+      b = this[i];
+      c = input[(m = input.length - closed) - 1];
+      j = -1;
+      while (++j < m) {
+        d = input[j];
+        if (d3_geom_polygonInside(d, a, b)) {
+          if (!d3_geom_polygonInside(c, a, b)) {
+            subject.push(d3_geom_polygonIntersect(c, d, a, b));
+          }
+          subject.push(d);
+        } else if (d3_geom_polygonInside(c, a, b)) {
+          subject.push(d3_geom_polygonIntersect(c, d, a, b));
+        }
+        c = d;
+      }
+      if (closed) subject.push(subject[0]);
+      a = b;
+    }
+    return subject;
+  };
+  function d3_geom_polygonInside(p, a, b) {
+    return (b[0] - a[0]) * (p[1] - a[1]) < (b[1] - a[1]) * (p[0] - a[0]);
+  }
+  function d3_geom_polygonIntersect(c, d, a, b) {
+    var x1 = c[0], x3 = a[0], x21 = d[0] - x1, x43 = b[0] - x3, y1 = c[1], y3 = a[1], y21 = d[1] - y1, y43 = b[1] - y3, ua = (x43 * (y1 - y3) - y43 * (x1 - x3)) / (y43 * x21 - x43 * y21);
+    return [ x1 + ua * x21, y1 + ua * y21 ];
+  }
+  function d3_geom_polygonClosed(coordinates) {
+    var a = coordinates[0], b = coordinates[coordinates.length - 1];
+    return !(a[0] - b[0] || a[1] - b[1]);
+  }
+  var d3_geom_voronoiEdges, d3_geom_voronoiCells, d3_geom_voronoiBeaches, d3_geom_voronoiBeachPool = [], d3_geom_voronoiFirstCircle, d3_geom_voronoiCircles, d3_geom_voronoiCirclePool = [];
+  function d3_geom_voronoiBeach() {
+    d3_geom_voronoiRedBlackNode(this);
+    this.edge = this.site = this.circle = null;
+  }
+  function d3_geom_voronoiCreateBeach(site) {
+    var beach = d3_geom_voronoiBeachPool.pop() || new d3_geom_voronoiBeach();
+    beach.site = site;
+    return beach;
+  }
+  function d3_geom_voronoiDetachBeach(beach) {
+    d3_geom_voronoiDetachCircle(beach);
+    d3_geom_voronoiBeaches.remove(beach);
+    d3_geom_voronoiBeachPool.push(beach);
+    d3_geom_voronoiRedBlackNode(beach);
+  }
+  function d3_geom_voronoiRemoveBeach(beach) {
+    var circle = beach.circle, x = circle.x, y = circle.cy, vertex = {
+      x: x,
+      y: y
+    }, previous = beach.P, next = beach.N, disappearing = [ beach ];
+    d3_geom_voronoiDetachBeach(beach);
+    var lArc = previous;
+    while (lArc.circle && abs(x - lArc.circle.x) < ε && abs(y - lArc.circle.cy) < ε) {
+      previous = lArc.P;
+      disappearing.unshift(lArc);
+      d3_geom_voronoiDetachBeach(lArc);
+      lArc = previous;
+    }
+    disappearing.unshift(lArc);
+    d3_geom_voronoiDetachCircle(lArc);
+    var rArc = next;
+    while (rArc.circle && abs(x - rArc.circle.x) < ε && abs(y - rArc.circle.cy) < ε) {
+      next = rArc.N;
+      disappearing.push(rArc);
+      d3_geom_voronoiDetachBeach(rArc);
+      rArc = next;
+    }
+    disappearing.push(rArc);
+    d3_geom_voronoiDetachCircle(rArc);
+    var nArcs = disappearing.length, iArc;
+    for (iArc = 1; iArc < nArcs; ++iArc) {
+      rArc = disappearing[iArc];
+      lArc = disappearing[iArc - 1];
+      d3_geom_voronoiSetEdgeEnd(rArc.edge, lArc.site, rArc.site, vertex);
+    }
+    lArc = disappearing[0];
+    rArc = disappearing[nArcs - 1];
+    rArc.edge = d3_geom_voronoiCreateEdge(lArc.site, rArc.site, null, vertex);
+    d3_geom_voronoiAttachCircle(lArc);
+    d3_geom_voronoiAttachCircle(rArc);
+  }
+  function d3_geom_voronoiAddBeach(site) {
+    var x = site.x, directrix = site.y, lArc, rArc, dxl, dxr, node = d3_geom_voronoiBeaches._;
+    while (node) {
+      dxl = d3_geom_voronoiLeftBreakPoint(node, directrix) - x;
+      if (dxl > ε) node = node.L; else {
+        dxr = x - d3_geom_voronoiRightBreakPoint(node, directrix);
+        if (dxr > ε) {
+          if (!node.R) {
+            lArc = node;
+            break;
+          }
+          node = node.R;
+        } else {
+          if (dxl > -ε) {
+            lArc = node.P;
+            rArc = node;
+          } else if (dxr > -ε) {
+            lArc = node;
+            rArc = node.N;
+          } else {
+            lArc = rArc = node;
+          }
+          break;
+        }
+      }
+    }
+    var newArc = d3_geom_voronoiCreateBeach(site);
+    d3_geom_voronoiBeaches.insert(lArc, newArc);
+    if (!lArc && !rArc) return;
+    if (lArc === rArc) {
+      d3_geom_voronoiDetachCircle(lArc);
+      rArc = d3_geom_voronoiCreateBeach(lArc.site);
+      d3_geom_voronoiBeaches.insert(newArc, rArc);
+      newArc.edge = rArc.edge = d3_geom_voronoiCreateEdge(lArc.site, newArc.site);
+      d3_geom_voronoiAttachCircle(lArc);
+      d3_geom_voronoiAttachCircle(rArc);
+      return;
+    }
+    if (!rArc) {
+      newArc.edge = d3_geom_voronoiCreateEdge(lArc.site, newArc.site);
+      return;
+    }
+    d3_geom_voronoiDetachCircle(lArc);
+    d3_geom_voronoiDetachCircle(rArc);
+    var lSite = lArc.site, ax = lSite.x, ay = lSite.y, bx = site.x - ax, by = site.y - ay, rSite = rArc.site, cx = rSite.x - ax, cy = rSite.y - ay, d = 2 * (bx * cy - by * cx), hb = bx * bx + by * by, hc = cx * cx + cy * cy, vertex = {
+      x: (cy * hb - by * hc) / d + ax,
+      y: (bx * hc - cx * hb) / d + ay
+    };
+    d3_geom_voronoiSetEdgeEnd(rArc.edge, lSite, rSite, vertex);
+    newArc.edge = d3_geom_voronoiCreateEdge(lSite, site, null, vertex);
+    rArc.edge = d3_geom_voronoiCreateEdge(site, rSite, null, vertex);
+    d3_geom_voronoiAttachCircle(lArc);
+    d3_geom_voronoiAttachCircle(rArc);
+  }
+  function d3_geom_voronoiLeftBreakPoint(arc, directrix) {
+    var site = arc.site, rfocx = site.x, rfocy = site.y, pby2 = rfocy - directrix;
+    if (!pby2) return rfocx;
+    var lArc = arc.P;
+    if (!lArc) return -Infinity;
+    site = lArc.site;
+    var lfocx = site.x, lfocy = site.y, plby2 = lfocy - directrix;
+    if (!plby2) return lfocx;
+    var hl = lfocx - rfocx, aby2 = 1 / pby2 - 1 / plby2, b = hl / plby2;
+    if (aby2) return (-b + Math.sqrt(b * b - 2 * aby2 * (hl * hl / (-2 * plby2) - lfocy + plby2 / 2 + rfocy - pby2 / 2))) / aby2 + rfocx;
+    return (rfocx + lfocx) / 2;
+  }
+  function d3_geom_voronoiRightBreakPoint(arc, directrix) {
+    var rArc = arc.N;
+    if (rArc) return d3_geom_voronoiLeftBreakPoint(rArc, directrix);
+    var site = arc.site;
+    return site.y === directrix ? site.x : Infinity;
+  }
+  function d3_geom_voronoiCell(site) {
+    this.site = site;
+    this.edges = [];
+  }
+  d3_geom_voronoiCell.prototype.prepare = function() {
+    var halfEdges = this.edges, iHalfEdge = halfEdges.length, edge;
+    while (iHalfEdge--) {
+      edge = halfEdges[iHalfEdge].edge;
+      if (!edge.b || !edge.a) halfEdges.splice(iHalfEdge, 1);
+    }
+    halfEdges.sort(d3_geom_voronoiHalfEdgeOrder);
+    return halfEdges.length;
+  };
+  function d3_geom_voronoiCloseCells(extent) {
+    var x0 = extent[0][0], x1 = extent[1][0], y0 = extent[0][1], y1 = extent[1][1], x2, y2, x3, y3, cells = d3_geom_voronoiCells, iCell = cells.length, cell, iHalfEdge, halfEdges, nHalfEdges, start, end;
+    while (iCell--) {
+      cell = cells[iCell];
+      if (!cell || !cell.prepare()) continue;
+      halfEdges = cell.edges;
+      nHalfEdges = halfEdges.length;
+      iHalfEdge = 0;
+      while (iHalfEdge < nHalfEdges) {
+        end = halfEdges[iHalfEdge].end(), x3 = end.x, y3 = end.y;
+        start = halfEdges[++iHalfEdge % nHalfEdges].start(), x2 = start.x, y2 = start.y;
+        if (abs(x3 - x2) > ε || abs(y3 - y2) > ε) {
+          halfEdges.splice(iHalfEdge, 0, new d3_geom_voronoiHalfEdge(d3_geom_voronoiCreateBorderEdge(cell.site, end, abs(x3 - x0) < ε && y1 - y3 > ε ? {
+            x: x0,
+            y: abs(x2 - x0) < ε ? y2 : y1
+          } : abs(y3 - y1) < ε && x1 - x3 > ε ? {
+            x: abs(y2 - y1) < ε ? x2 : x1,
+            y: y1
+          } : abs(x3 - x1) < ε && y3 - y0 > ε ? {
+            x: x1,
+            y: abs(x2 - x1) < ε ? y2 : y0
+          } : abs(y3 - y0) < ε && x3 - x0 > ε ? {
+            x: abs(y2 - y0) < ε ? x2 : x0,
+            y: y0
+          } : null), cell.site, null));
+          ++nHalfEdges;
+        }
+      }
+    }
+  }
+  function d3_geom_voronoiHalfEdgeOrder(a, b) {
+    return b.angle - a.angle;
+  }
+  function d3_geom_voronoiCircle() {
+    d3_geom_voronoiRedBlackNode(this);
+    this.x = this.y = this.arc = this.site = this.cy = null;
+  }
+  function d3_geom_voronoiAttachCircle(arc) {
+    var lArc = arc.P, rArc = arc.N;
+    if (!lArc || !rArc) return;
+    var lSite = lArc.site, cSite = arc.site, rSite = rArc.site;
+    if (lSite === rSite) return;
+    var bx = cSite.x, by = cSite.y, ax = lSite.x - bx, ay = lSite.y - by, cx = rSite.x - bx, cy = rSite.y - by;
+    var d = 2 * (ax * cy - ay * cx);
+    if (d >= -ε2) return;
+    var ha = ax * ax + ay * ay, hc = cx * cx + cy * cy, x = (cy * ha - ay * hc) / d, y = (ax * hc - cx * ha) / d, cy = y + by;
+    var circle = d3_geom_voronoiCirclePool.pop() || new d3_geom_voronoiCircle();
+    circle.arc = arc;
+    circle.site = cSite;
+    circle.x = x + bx;
+    circle.y = cy + Math.sqrt(x * x + y * y);
+    circle.cy = cy;
+    arc.circle = circle;
+    var before = null, node = d3_geom_voronoiCircles._;
+    while (node) {
+      if (circle.y < node.y || circle.y === node.y && circle.x <= node.x) {
+        if (node.L) node = node.L; else {
+          before = node.P;
+          break;
+        }
+      } else {
+        if (node.R) node = node.R; else {
+          before = node;
+          break;
+        }
+      }
+    }
+    d3_geom_voronoiCircles.insert(before, circle);
+    if (!before) d3_geom_voronoiFirstCircle = circle;
+  }
+  function d3_geom_voronoiDetachCircle(arc) {
+    var circle = arc.circle;
+    if (circle) {
+      if (!circle.P) d3_geom_voronoiFirstCircle = circle.N;
+      d3_geom_voronoiCircles.remove(circle);
+      d3_geom_voronoiCirclePool.push(circle);
+      d3_geom_voronoiRedBlackNode(circle);
+      arc.circle = null;
+    }
+  }
+  function d3_geom_voronoiClipEdges(extent) {
+    var edges = d3_geom_voronoiEdges, clip = d3_geom_clipLine(extent[0][0], extent[0][1], extent[1][0], extent[1][1]), i = edges.length, e;
+    while (i--) {
+      e = edges[i];
+      if (!d3_geom_voronoiConnectEdge(e, extent) || !clip(e) || abs(e.a.x - e.b.x) < ε && abs(e.a.y - e.b.y) < ε) {
+        e.a = e.b = null;
+        edges.splice(i, 1);
+      }
+    }
+  }
+  function d3_geom_voronoiConnectEdge(edge, extent) {
+    var vb = edge.b;
+    if (vb) return true;
+    var va = edge.a, x0 = extent[0][0], x1 = extent[1][0], y0 = extent[0][1], y1 = extent[1][1], lSite = edge.l, rSite = edge.r, lx = lSite.x, ly = lSite.y, rx = rSite.x, ry = rSite.y, fx = (lx + rx) / 2, fy = (ly + ry) / 2, fm, fb;
+    if (ry === ly) {
+      if (fx < x0 || fx >= x1) return;
+      if (lx > rx) {
+        if (!va) va = {
+          x: fx,
+          y: y0
+        }; else if (va.y >= y1) return;
+        vb = {
+          x: fx,
+          y: y1
+        };
+      } else {
+        if (!va) va = {
+          x: fx,
+          y: y1
+        }; else if (va.y < y0) return;
+        vb = {
+          x: fx,
+          y: y0
+        };
+      }
+    } else {
+      fm = (lx - rx) / (ry - ly);
+      fb = fy - fm * fx;
+      if (fm < -1 || fm > 1) {
+        if (lx > rx) {
+          if (!va) va = {
+            x: (y0 - fb) / fm,
+            y: y0
+          }; else if (va.y >= y1) return;
+          vb = {
+            x: (y1 - fb) / fm,
+            y: y1
+          };
+        } else {
+          if (!va) va = {
+            x: (y1 - fb) / fm,
+            y: y1
+          }; else if (va.y < y0) return;
+          vb = {
+            x: (y0 - fb) / fm,
+            y: y0
+          };
+        }
+      } else {
+        if (ly < ry) {
+          if (!va) va = {
+            x: x0,
+            y: fm * x0 + fb
+          }; else if (va.x >= x1) return;
+          vb = {
+            x: x1,
+            y: fm * x1 + fb
+          };
+        } else {
+          if (!va) va = {
+            x: x1,
+            y: fm * x1 + fb
+          }; else if (va.x < x0) return;
+          vb = {
+            x: x0,
+            y: fm * x0 + fb
+          };
+        }
+      }
+    }
+    edge.a = va;
+    edge.b = vb;
+    return true;
+  }
+  function d3_geom_voronoiEdge(lSite, rSite) {
+    this.l = lSite;
+    this.r = rSite;
+    this.a = this.b = null;
+  }
+  function d3_geom_voronoiCreateEdge(lSite, rSite, va, vb) {
+    var edge = new d3_geom_voronoiEdge(lSite, rSite);
+    d3_geom_voronoiEdges.push(edge);
+    if (va) d3_geom_voronoiSetEdgeEnd(edge, lSite, rSite, va);
+    if (vb) d3_geom_voronoiSetEdgeEnd(edge, rSite, lSite, vb);
+    d3_geom_voronoiCells[lSite.i].edges.push(new d3_geom_voronoiHalfEdge(edge, lSite, rSite));
+    d3_geom_voronoiCells[rSite.i].edges.push(new d3_geom_voronoiHalfEdge(edge, rSite, lSite));
+    return edge;
+  }
+  function d3_geom_voronoiCreateBorderEdge(lSite, va, vb) {
+    var edge = new d3_geom_voronoiEdge(lSite, null);
+    edge.a = va;
+    edge.b = vb;
+    d3_geom_voronoiEdges.push(edge);
+    return edge;
+  }
+  function d3_geom_voronoiSetEdgeEnd(edge, lSite, rSite, vertex) {
+    if (!edge.a && !edge.b) {
+      edge.a = vertex;
+      edge.l = lSite;
+      edge.r = rSite;
+    } else if (edge.l === rSite) {
+      edge.b = vertex;
+    } else {
+      edge.a = vertex;
+    }
+  }
+  function d3_geom_voronoiHalfEdge(edge, lSite, rSite) {
+    var va = edge.a, vb = edge.b;
+    this.edge = edge;
+    this.site = lSite;
+    this.angle = rSite ? Math.atan2(rSite.y - lSite.y, rSite.x - lSite.x) : edge.l === lSite ? Math.atan2(vb.x - va.x, va.y - vb.y) : Math.atan2(va.x - vb.x, vb.y - va.y);
+  }
+  d3_geom_voronoiHalfEdge.prototype = {
+    start: function() {
+      return this.edge.l === this.site ? this.edge.a : this.edge.b;
+    },
+    end: function() {
+      return this.edge.l === this.site ? this.edge.b : this.edge.a;
+    }
+  };
+  function d3_geom_voronoiRedBlackTree() {
+    this._ = null;
+  }
+  function d3_geom_voronoiRedBlackNode(node) {
+    node.U = node.C = node.L = node.R = node.P = node.N = null;
+  }
+  d3_geom_voronoiRedBlackTree.prototype = {
+    insert: function(after, node) {
+      var parent, grandpa, uncle;
+      if (after) {
+        node.P = after;
+        node.N = after.N;
+        if (after.N) after.N.P = node;
+        after.N = node;
+        if (after.R) {
+          after = after.R;
+          while (after.L) after = after.L;
+          after.L = node;
+        } else {
+          after.R = node;
+        }
+        parent = after;
+      } else if (this._) {
+        after = d3_geom_voronoiRedBlackFirst(this._);
+        node.P = null;
+        node.N = after;
+        after.P = after.L = node;
+        parent = after;
+      } else {
+        node.P = node.N = null;
+        this._ = node;
+        parent = null;
+      }
+      node.L = node.R = null;
+      node.U = parent;
+      node.C = true;
+      after = node;
+      while (parent && parent.C) {
+        grandpa = parent.U;
+        if (parent === grandpa.L) {
+          uncle = grandpa.R;
+          if (uncle && uncle.C) {
+            parent.C = uncle.C = false;
+            grandpa.C = true;
+            after = grandpa;
+          } else {
+            if (after === parent.R) {
+              d3_geom_voronoiRedBlackRotateLeft(this, parent);
+              after = parent;
+              parent = after.U;
+            }
+            parent.C = false;
+            grandpa.C = true;
+            d3_geom_voronoiRedBlackRotateRight(this, grandpa);
+          }
+        } else {
+          uncle = grandpa.L;
+          if (uncle && uncle.C) {
+            parent.C = uncle.C = false;
+            grandpa.C = true;
+            after = grandpa;
+          } else {
+            if (after === parent.L) {
+              d3_geom_voronoiRedBlackRotateRight(this, parent);
+              after = parent;
+              parent = after.U;
+            }
+            parent.C = false;
+            grandpa.C = true;
+            d3_geom_voronoiRedBlackRotateLeft(this, grandpa);
+          }
+        }
+        parent = after.U;
+      }
+      this._.C = false;
+    },
+    remove: function(node) {
+      if (node.N) node.N.P = node.P;
+      if (node.P) node.P.N = node.N;
+      node.N = node.P = null;
+      var parent = node.U, sibling, left = node.L, right = node.R, next, red;
+      if (!left) next = right; else if (!right) next = left; else next = d3_geom_voronoiRedBlackFirst(right);
+      if (parent) {
+        if (parent.L === node) parent.L = next; else parent.R = next;
+      } else {
+        this._ = next;
+      }
+      if (left && right) {
+        red = next.C;
+        next.C = node.C;
+        next.L = left;
+        left.U = next;
+        if (next !== right) {
+          parent = next.U;
+          next.U = node.U;
+          node = next.R;
+          parent.L = node;
+          next.R = right;
+          right.U = next;
+        } else {
+          next.U = parent;
+          parent = next;
+          node = next.R;
+        }
+      } else {
+        red = node.C;
+        node = next;
+      }
+      if (node) node.U = parent;
+      if (red) return;
+      if (node && node.C) {
+        node.C = false;
+        return;
+      }
+      do {
+        if (node === this._) break;
+        if (node === parent.L) {
+          sibling = parent.R;
+          if (sibling.C) {
+            sibling.C = false;
+            parent.C = true;
+            d3_geom_voronoiRedBlackRotateLeft(this, parent);
+            sibling = parent.R;
+          }
+          if (sibling.L && sibling.L.C || sibling.R && sibling.R.C) {
+            if (!sibling.R || !sibling.R.C) {
+              sibling.L.C = false;
+              sibling.C = true;
+              d3_geom_voronoiRedBlackRotateRight(this, sibling);
+              sibling = parent.R;
+            }
+            sibling.C = parent.C;
+            parent.C = sibling.R.C = false;
+            d3_geom_voronoiRedBlackRotateLeft(this, parent);
+            node = this._;
+            break;
+          }
+        } else {
+          sibling = parent.L;
+          if (sibling.C) {
+            sibling.C = false;
+            parent.C = true;
+            d3_geom_voronoiRedBlackRotateRight(this, parent);
+            sibling = parent.L;
+          }
+          if (sibling.L && sibling.L.C || sibling.R && sibling.R.C) {
+            if (!sibling.L || !sibling.L.C) {
+              sibling.R.C = false;
+              sibling.C = true;
+              d3_geom_voronoiRedBlackRotateLeft(this, sibling);
+              sibling = parent.L;
+            }
+            sibling.C = parent.C;
+            parent.C = sibling.L.C = false;
+            d3_geom_voronoiRedBlackRotateRight(this, parent);
+            node = this._;
+            break;
+          }
+        }
+        sibling.C = true;
+        node = parent;
+        parent = parent.U;
+      } while (!node.C);
+      if (node) node.C = false;
+    }
+  };
+  function d3_geom_voronoiRedBlackRotateLeft(tree, node) {
+    var p = node, q = node.R, parent = p.U;
+    if (parent) {
+      if (parent.L === p) parent.L = q; else parent.R = q;
+    } else {
+      tree._ = q;
+    }
+    q.U = parent;
+    p.U = q;
+    p.R = q.L;
+    if (p.R) p.R.U = p;
+    q.L = p;
+  }
+  function d3_geom_voronoiRedBlackRotateRight(tree, node) {
+    var p = node, q = node.L, parent = p.U;
+    if (parent) {
+      if (parent.L === p) parent.L = q; else parent.R = q;
+    } else {
+      tree._ = q;
+    }
+    q.U = parent;
+    p.U = q;
+    p.L = q.R;
+    if (p.L) p.L.U = p;
+    q.R = p;
+  }
+  function d3_geom_voronoiRedBlackFirst(node) {
+    while (node.L) node = node.L;
+    return node;
+  }
+  function d3_geom_voronoi(sites, bbox) {
+    var site = sites.sort(d3_geom_voronoiVertexOrder).pop(), x0, y0, circle;
+    d3_geom_voronoiEdges = [];
+    d3_geom_voronoiCells = new Array(sites.length);
+    d3_geom_voronoiBeaches = new d3_geom_voronoiRedBlackTree();
+    d3_geom_voronoiCircles = new d3_geom_voronoiRedBlackTree();
+    while (true) {
+      circle = d3_geom_voronoiFirstCircle;
+      if (site && (!circle || site.y < circle.y || site.y === circle.y && site.x < circle.x)) {
+        if (site.x !== x0 || site.y !== y0) {
+          d3_geom_voronoiCells[site.i] = new d3_geom_voronoiCell(site);
+          d3_geom_voronoiAddBeach(site);
+          x0 = site.x, y0 = site.y;
+        }
+        site = sites.pop();
+      } else if (circle) {
+        d3_geom_voronoiRemoveBeach(circle.arc);
+      } else {
+        break;
+      }
+    }
+    if (bbox) d3_geom_voronoiClipEdges(bbox), d3_geom_voronoiCloseCells(bbox);
+    var diagram = {
+      cells: d3_geom_voronoiCells,
+      edges: d3_geom_voronoiEdges
+    };
+    d3_geom_voronoiBeaches = d3_geom_voronoiCircles = d3_geom_voronoiEdges = d3_geom_voronoiCells = null;
+    return diagram;
+  }
+  function d3_geom_voronoiVertexOrder(a, b) {
+    return b.y - a.y || b.x - a.x;
+  }
+  d3.geom.voronoi = function(points) {
+    var x = d3_geom_pointX, y = d3_geom_pointY, fx = x, fy = y, clipExtent = d3_geom_voronoiClipExtent;
+    if (points) return voronoi(points);
+    function voronoi(data) {
+      var polygons = new Array(data.length), x0 = clipExtent[0][0], y0 = clipExtent[0][1], x1 = clipExtent[1][0], y1 = clipExtent[1][1];
+      d3_geom_voronoi(sites(data), clipExtent).cells.forEach(function(cell, i) {
+        var edges = cell.edges, site = cell.site, polygon = polygons[i] = edges.length ? edges.map(function(e) {
+          var s = e.start();
+          return [ s.x, s.y ];
+        }) : site.x >= x0 && site.x <= x1 && site.y >= y0 && site.y <= y1 ? [ [ x0, y1 ], [ x1, y1 ], [ x1, y0 ], [ x0, y0 ] ] : [];
+        polygon.point = data[i];
+      });
+      return polygons;
+    }
+    function sites(data) {
+      return data.map(function(d, i) {
+        return {
+          x: Math.round(fx(d, i) / ε) * ε,
+          y: Math.round(fy(d, i) / ε) * ε,
+          i: i
+        };
+      });
+    }
+    voronoi.links = function(data) {
+      return d3_geom_voronoi(sites(data)).edges.filter(function(edge) {
+        return edge.l && edge.r;
+      }).map(function(edge) {
+        return {
+          source: data[edge.l.i],
+          target: data[edge.r.i]
+        };
+      });
+    };
+    voronoi.triangles = function(data) {
+      var triangles = [];
+      d3_geom_voronoi(sites(data)).cells.forEach(function(cell, i) {
+        var site = cell.site, edges = cell.edges.sort(d3_geom_voronoiHalfEdgeOrder), j = -1, m = edges.length, e0, s0, e1 = edges[m - 1].edge, s1 = e1.l === site ? e1.r : e1.l;
+        while (++j < m) {
+          e0 = e1;
+          s0 = s1;
+          e1 = edges[j].edge;
+          s1 = e1.l === site ? e1.r : e1.l;
+          if (i < s0.i && i < s1.i && d3_geom_voronoiTriangleArea(site, s0, s1) < 0) {
+            triangles.push([ data[i], data[s0.i], data[s1.i] ]);
+          }
+        }
+      });
+      return triangles;
+    };
+    voronoi.x = function(_) {
+      return arguments.length ? (fx = d3_functor(x = _), voronoi) : x;
+    };
+    voronoi.y = function(_) {
+      return arguments.length ? (fy = d3_functor(y = _), voronoi) : y;
+    };
+    voronoi.clipExtent = function(_) {
+      if (!arguments.length) return clipExtent === d3_geom_voronoiClipExtent ? null : clipExtent;
+      clipExtent = _ == null ? d3_geom_voronoiClipExtent : _;
+      return voronoi;
+    };
+    voronoi.size = function(_) {
+      if (!arguments.length) return clipExtent === d3_geom_voronoiClipExtent ? null : clipExtent && clipExtent[1];
+      return voronoi.clipExtent(_ && [ [ 0, 0 ], _ ]);
+    };
+    return voronoi;
+  };
+  var d3_geom_voronoiClipExtent = [ [ -1e6, -1e6 ], [ 1e6, 1e6 ] ];
+  function d3_geom_voronoiTriangleArea(a, b, c) {
+    return (a.x - c.x) * (b.y - a.y) - (a.x - b.x) * (c.y - a.y);
+  }
+  d3.geom.delaunay = function(vertices) {
+    return d3.geom.voronoi().triangles(vertices);
+  };
+  d3.geom.quadtree = function(points, x1, y1, x2, y2) {
+    var x = d3_geom_pointX, y = d3_geom_pointY, compat;
+    if (compat = arguments.length) {
+      x = d3_geom_quadtreeCompatX;
+      y = d3_geom_quadtreeCompatY;
+      if (compat === 3) {
+        y2 = y1;
+        x2 = x1;
+        y1 = x1 = 0;
+      }
+      return quadtree(points);
+    }
+    function quadtree(data) {
+      var d, fx = d3_functor(x), fy = d3_functor(y), xs, ys, i, n, x1_, y1_, x2_, y2_;
+      if (x1 != null) {
+        x1_ = x1, y1_ = y1, x2_ = x2, y2_ = y2;
+      } else {
+        x2_ = y2_ = -(x1_ = y1_ = Infinity);
+        xs = [], ys = [];
+        n = data.length;
+        if (compat) for (i = 0; i < n; ++i) {
+          d = data[i];
+          if (d.x < x1_) x1_ = d.x;
+          if (d.y < y1_) y1_ = d.y;
+          if (d.x > x2_) x2_ = d.x;
+          if (d.y > y2_) y2_ = d.y;
+          xs.push(d.x);
+          ys.push(d.y);
+        } else for (i = 0; i < n; ++i) {
+          var x_ = +fx(d = data[i], i), y_ = +fy(d, i);
+          if (x_ < x1_) x1_ = x_;
+          if (y_ < y1_) y1_ = y_;
+          if (x_ > x2_) x2_ = x_;
+          if (y_ > y2_) y2_ = y_;
+          xs.push(x_);
+          ys.push(y_);
+        }
+      }
+      var dx = x2_ - x1_, dy = y2_ - y1_;
+      if (dx > dy) y2_ = y1_ + dx; else x2_ = x1_ + dy;
+      function insert(n, d, x, y, x1, y1, x2, y2) {
+        if (isNaN(x) || isNaN(y)) return;
+        if (n.leaf) {
+          var nx = n.x, ny = n.y;
+          if (nx != null) {
+            if (abs(nx - x) + abs(ny - y) < .01) {
+              insertChild(n, d, x, y, x1, y1, x2, y2);
+            } else {
+              var nPoint = n.point;
+              n.x = n.y = n.point = null;
+              insertChild(n, nPoint, nx, ny, x1, y1, x2, y2);
+              insertChild(n, d, x, y, x1, y1, x2, y2);
+            }
+          } else {
+            n.x = x, n.y = y, n.point = d;
+          }
+        } else {
+          insertChild(n, d, x, y, x1, y1, x2, y2);
+        }
+      }
+      function insertChild(n, d, x, y, x1, y1, x2, y2) {
+        var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, right = x >= sx, bottom = y >= sy, i = (bottom << 1) + right;
+        n.leaf = false;
+        n = n.nodes[i] || (n.nodes[i] = d3_geom_quadtreeNode());
+        if (right) x1 = sx; else x2 = sx;
+        if (bottom) y1 = sy; else y2 = sy;
+        insert(n, d, x, y, x1, y1, x2, y2);
+      }
+      var root = d3_geom_quadtreeNode();
+      root.add = function(d) {
+        insert(root, d, +fx(d, ++i), +fy(d, i), x1_, y1_, x2_, y2_);
+      };
+      root.visit = function(f) {
+        d3_geom_quadtreeVisit(f, root, x1_, y1_, x2_, y2_);
+      };
+      i = -1;
+      if (x1 == null) {
+        while (++i < n) {
+          insert(root, data[i], xs[i], ys[i], x1_, y1_, x2_, y2_);
+        }
+        --i;
+      } else data.forEach(root.add);
+      xs = ys = data = d = null;
+      return root;
+    }
+    quadtree.x = function(_) {
+      return arguments.length ? (x = _, quadtree) : x;
+    };
+    quadtree.y = function(_) {
+      return arguments.length ? (y = _, quadtree) : y;
+    };
+    quadtree.extent = function(_) {
+      if (!arguments.length) return x1 == null ? null : [ [ x1, y1 ], [ x2, y2 ] ];
+      if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = +_[0][0], y1 = +_[0][1], x2 = +_[1][0], 
+      y2 = +_[1][1];
+      return quadtree;
+    };
+    quadtree.size = function(_) {
+      if (!arguments.length) return x1 == null ? null : [ x2 - x1, y2 - y1 ];
+      if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = y1 = 0, x2 = +_[0], y2 = +_[1];
+      return quadtree;
+    };
+    return quadtree;
+  };
+  function d3_geom_quadtreeCompatX(d) {
+    return d.x;
+  }
+  function d3_geom_quadtreeCompatY(d) {
+    return d.y;
+  }
+  function d3_geom_quadtreeNode() {
+    return {
+      leaf: true,
+      nodes: [],
+      point: null,
+      x: null,
+      y: null
+    };
+  }
+  function d3_geom_quadtreeVisit(f, node, x1, y1, x2, y2) {
+    if (!f(node, x1, y1, x2, y2)) {
+      var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, children = node.nodes;
+      if (children[0]) d3_geom_quadtreeVisit(f, children[0], x1, y1, sx, sy);
+      if (children[1]) d3_geom_quadtreeVisit(f, children[1], sx, y1, x2, sy);
+      if (children[2]) d3_geom_quadtreeVisit(f, children[2], x1, sy, sx, y2);
+      if (children[3]) d3_geom_quadtreeVisit(f, children[3], sx, sy, x2, y2);
+    }
+  }
+  d3.interpolateRgb = d3_interpolateRgb;
+  function d3_interpolateRgb(a, b) {
+    a = d3.rgb(a);
+    b = d3.rgb(b);
+    var ar = a.r, ag = a.g, ab = a.b, br = b.r - ar, bg = b.g - ag, bb = b.b - ab;
+    return function(t) {
+      return "#" + d3_rgb_hex(Math.round(ar + br * t)) + d3_rgb_hex(Math.round(ag + bg * t)) + d3_rgb_hex(Math.round(ab + bb * t));
+    };
+  }
+  d3.interpolateObject = d3_interpolateObject;
+  function d3_interpolateObject(a, b) {
+    var i = {}, c = {}, k;
+    for (k in a) {
+      if (k in b) {
+        i[k] = d3_interpolate(a[k], b[k]);
+      } else {
+        c[k] = a[k];
+      }
+    }
+    for (k in b) {
+      if (!(k in a)) {
+        c[k] = b[k];
+      }
+    }
+    return function(t) {
+      for (k in i) c[k] = i[k](t);
+      return c;
+    };
+  }
+  d3.interpolateNumber = d3_interpolateNumber;
+  function d3_interpolateNumber(a, b) {
+    b -= a = +a;
+    return function(t) {
+      return a + b * t;
+    };
+  }
+  d3.interpolateString = d3_interpolateString;
+  function d3_interpolateString(a, b) {
+    var m, i, j, s0 = 0, s1 = 0, s = [], q = [], n, o;
+    a = a + "", b = b + "";
+    d3_interpolate_number.lastIndex = 0;
+    for (i = 0; m = d3_interpolate_number.exec(b); ++i) {
+      if (m.index) s.push(b.substring(s0, s1 = m.index));
+      q.push({
+        i: s.length,
+        x: m[0]
+      });
+      s.push(null);
+      s0 = d3_interpolate_number.lastIndex;
+    }
+    if (s0 < b.length) s.push(b.substring(s0));
+    for (i = 0, n = q.length; (m = d3_interpolate_number.exec(a)) && i < n; ++i) {
+      o = q[i];
+      if (o.x == m[0]) {
+        if (o.i) {
+          if (s[o.i + 1] == null) {
+            s[o.i - 1] += o.x;
+            s.splice(o.i, 1);
+            for (j = i + 1; j < n; ++j) q[j].i--;
+          } else {
+            s[o.i - 1] += o.x + s[o.i + 1];
+            s.splice(o.i, 2);
+            for (j = i + 1; j < n; ++j) q[j].i -= 2;
+          }
+        } else {
+          if (s[o.i + 1] == null) {
+            s[o.i] = o.x;
+          } else {
+            s[o.i] = o.x + s[o.i + 1];
+            s.splice(o.i + 1, 1);
+            for (j = i + 1; j < n; ++j) q[j].i--;
+          }
+        }
+        q.splice(i, 1);
+        n--;
+        i--;
+      } else {
+        o.x = d3_interpolateNumber(parseFloat(m[0]), parseFloat(o.x));
+      }
+    }
+    while (i < n) {
+      o = q.pop();
+      if (s[o.i + 1] == null) {
+        s[o.i] = o.x;
+      } else {
+        s[o.i] = o.x + s[o.i + 1];
+        s.splice(o.i + 1, 1);
+      }
+      n--;
+    }
+    if (s.length === 1) {
+      return s[0] == null ? (o = q[0].x, function(t) {
+        return o(t) + "";
+      }) : function() {
+        return b;
+      };
+    }
+    return function(t) {
+      for (i = 0; i < n; ++i) s[(o = q[i]).i] = o.x(t);
+      return s.join("");
+    };
+  }
+  var d3_interpolate_number = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g;
+  d3.interpolate = d3_interpolate;
+  function d3_interpolate(a, b) {
+    var i = d3.interpolators.length, f;
+    while (--i >= 0 && !(f = d3.interpolators[i](a, b))) ;
+    return f;
+  }
+  d3.interpolators = [ function(a, b) {
+    var t = typeof b;
+    return (t === "string" ? d3_rgb_names.has(b) || /^(#|rgb\(|hsl\()/.test(b) ? d3_interpolateRgb : d3_interpolateString : b instanceof d3_Color ? d3_interpolateRgb : Array.isArray(b) ? d3_interpolateArray : t === "object" && isNaN(b) ? d3_interpolateObject : d3_interpolateNumber)(a, b);
+  } ];
+  d3.interpolateArray = d3_interpolateArray;
+  function d3_interpolateArray(a, b) {
+    var x = [], c = [], na = a.length, nb = b.length, n0 = Math.min(a.length, b.length), i;
+    for (i = 0; i < n0; ++i) x.push(d3_interpolate(a[i], b[i]));
+    for (;i < na; ++i) c[i] = a[i];
+    for (;i < nb; ++i) c[i] = b[i];
+    return function(t) {
+      for (i = 0; i < n0; ++i) c[i] = x[i](t);
+      return c;
+    };
+  }
+  var d3_ease_default = function() {
+    return d3_identity;
+  };
+  var d3_ease = d3.map({
+    linear: d3_ease_default,
+    poly: d3_ease_poly,
+    quad: function() {
+      return d3_ease_quad;
+    },
+    cubic: function() {
+      return d3_ease_cubic;
+    },
+    sin: function() {
+      return d3_ease_sin;
+    },
+    exp: function() {
+      return d3_ease_exp;
+    },
+    circle: function() {
+      return d3_ease_circle;
+    },
+    elastic: d3_ease_elastic,
+    back: d3_ease_back,
+    bounce: function() {
+      return d3_ease_bounce;
+    }
+  });
+  var d3_ease_mode = d3.map({
+    "in": d3_identity,
+    out: d3_ease_reverse,
+    "in-out": d3_ease_reflect,
+    "out-in": function(f) {
+      return d3_ease_reflect(d3_ease_reverse(f));
+    }
+  });
+  d3.ease = function(name) {
+    var i = name.indexOf("-"), t = i >= 0 ? name.substring(0, i) : name, m = i >= 0 ? name.substring(i + 1) : "in";
+    t = d3_ease.get(t) || d3_ease_default;
+    m = d3_ease_mode.get(m) || d3_identity;
+    return d3_ease_clamp(m(t.apply(null, d3_arraySlice.call(arguments, 1))));
+  };
+  function d3_ease_clamp(f) {
+    return function(t) {
+      return t <= 0 ? 0 : t >= 1 ? 1 : f(t);
+    };
+  }
+  function d3_ease_reverse(f) {
+    return function(t) {
+      return 1 - f(1 - t);
+    };
+  }
+  function d3_ease_reflect(f) {
+    return function(t) {
+      return .5 * (t < .5 ? f(2 * t) : 2 - f(2 - 2 * t));
+    };
+  }
+  function d3_ease_quad(t) {
+    return t * t;
+  }
+  function d3_ease_cubic(t) {
+    return t * t * t;
+  }
+  function d3_ease_cubicInOut(t) {
+    if (t <= 0) return 0;
+    if (t >= 1) return 1;
+    var t2 = t * t, t3 = t2 * t;
+    return 4 * (t < .5 ? t3 : 3 * (t - t2) + t3 - .75);
+  }
+  function d3_ease_poly(e) {
+    return function(t) {
+      return Math.pow(t, e);
+    };
+  }
+  function d3_ease_sin(t) {
+    return 1 - Math.cos(t * halfπ);
+  }
+  function d3_ease_exp(t) {
+    return Math.pow(2, 10 * (t - 1));
+  }
+  function d3_ease_circle(t) {
+    return 1 - Math.sqrt(1 - t * t);
+  }
+  function d3_ease_elastic(a, p) {
+    var s;
+    if (arguments.length < 2) p = .45;
+    if (arguments.length) s = p / τ * Math.asin(1 / a); else a = 1, s = p / 4;
+    return function(t) {
+      return 1 + a * Math.pow(2, -10 * t) * Math.sin((t - s) * τ / p);
+    };
+  }
+  function d3_ease_back(s) {
+    if (!s) s = 1.70158;
+    return function(t) {
+      return t * t * ((s + 1) * t - s);
+    };
+  }
+  function d3_ease_bounce(t) {
+    return t < 1 / 2.75 ? 7.5625 * t * t : t < 2 / 2.75 ? 7.5625 * (t -= 1.5 / 2.75) * t + .75 : t < 2.5 / 2.75 ? 7.5625 * (t -= 2.25 / 2.75) * t + .9375 : 7.5625 * (t -= 2.625 / 2.75) * t + .984375;
+  }
+  d3.interpolateHcl = d3_interpolateHcl;
+  function d3_interpolateHcl(a, b) {
+    a = d3.hcl(a);
+    b = d3.hcl(b);
+    var ah = a.h, ac = a.c, al = a.l, bh = b.h - ah, bc = b.c - ac, bl = b.l - al;
+    if (isNaN(bc)) bc = 0, ac = isNaN(ac) ? b.c : ac;
+    if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else if (bh > 180) bh -= 360; else if (bh < -180) bh += 360;
+    return function(t) {
+      return d3_hcl_lab(ah + bh * t, ac + bc * t, al + bl * t) + "";
+    };
+  }
+  d3.interpolateHsl = d3_interpolateHsl;
+  function d3_interpolateHsl(a, b) {
+    a = d3.hsl(a);
+    b = d3.hsl(b);
+    var ah = a.h, as = a.s, al = a.l, bh = b.h - ah, bs = b.s - as, bl = b.l - al;
+    if (isNaN(bs)) bs = 0, as = isNaN(as) ? b.s : as;
+    if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else if (bh > 180) bh -= 360; else if (bh < -180) bh += 360;
+    return function(t) {
+      return d3_hsl_rgb(ah + bh * t, as + bs * t, al + bl * t) + "";
+    };
+  }
+  d3.interpolateLab = d3_interpolateLab;
+  function d3_interpolateLab(a, b) {
+    a = d3.lab(a);
+    b = d3.lab(b);
+    var al = a.l, aa = a.a, ab = a.b, bl = b.l - al, ba = b.a - aa, bb = b.b - ab;
+    return function(t) {
+      return d3_lab_rgb(al + bl * t, aa + ba * t, ab + bb * t) + "";
+    };
+  }
+  d3.interpolateRound = d3_interpolateRound;
+  function d3_interpolateRound(a, b) {
+    b -= a;
+    return function(t) {
+      return Math.round(a + b * t);
+    };
+  }
+  d3.transform = function(string) {
+    var g = d3_document.createElementNS(d3.ns.prefix.svg, "g");
+    return (d3.transform = function(string) {
+      if (string != null) {
+        g.setAttribute("transform", string);
+        var t = g.transform.baseVal.consolidate();
+      }
+      return new d3_transform(t ? t.matrix : d3_transformIdentity);
+    })(string);
+  };
+  function d3_transform(m) {
+    var r0 = [ m.a, m.b ], r1 = [ m.c, m.d ], kx = d3_transformNormalize(r0), kz = d3_transformDot(r0, r1), ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz)) || 0;
+    if (r0[0] * r1[1] < r1[0] * r0[1]) {
+      r0[0] *= -1;
+      r0[1] *= -1;
+      kx *= -1;
+      kz *= -1;
+    }
+    this.rotate = (kx ? Math.atan2(r0[1], r0[0]) : Math.atan2(-r1[0], r1[1])) * d3_degrees;
+    this.translate = [ m.e, m.f ];
+    this.scale = [ kx, ky ];
+    this.skew = ky ? Math.atan2(kz, ky) * d3_degrees : 0;
+  }
+  d3_transform.prototype.toString = function() {
+    return "translate(" + this.translate + ")rotate(" + this.rotate + ")skewX(" + this.skew + ")scale(" + this.scale + ")";
+  };
+  function d3_transformDot(a, b) {
+    return a[0] * b[0] + a[1] * b[1];
+  }
+  function d3_transformNormalize(a) {
+    var k = Math.sqrt(d3_transformDot(a, a));
+    if (k) {
+      a[0] /= k;
+      a[1] /= k;
+    }
+    return k;
+  }
+  function d3_transformCombine(a, b, k) {
+    a[0] += k * b[0];
+    a[1] += k * b[1];
+    return a;
+  }
+  var d3_transformIdentity = {
+    a: 1,
+    b: 0,
+    c: 0,
+    d: 1,
+    e: 0,
+    f: 0
+  };
+  d3.interpolateTransform = d3_interpolateTransform;
+  function d3_interpolateTransform(a, b) {
+    var s = [], q = [], n, A = d3.transform(a), B = d3.transform(b), ta = A.translate, tb = B.translate, ra = A.rotate, rb = B.rotate, wa = A.skew, wb = B.skew, ka = A.scale, kb = B.scale;
+    if (ta[0] != tb[0] || ta[1] != tb[1]) {
+      s.push("translate(", null, ",", null, ")");
+      q.push({
+        i: 1,
+        x: d3_interpolateNumber(ta[0], tb[0])
+      }, {
+        i: 3,
+        x: d3_interpolateNumber(ta[1], tb[1])
+      });
+    } else if (tb[0] || tb[1]) {
+      s.push("translate(" + tb + ")");
+    } else {
+      s.push("");
+    }
+    if (ra != rb) {
+      if (ra - rb > 180) rb += 360; else if (rb - ra > 180) ra += 360;
+      q.push({
+        i: s.push(s.pop() + "rotate(", null, ")") - 2,
+        x: d3_interpolateNumber(ra, rb)
+      });
+    } else if (rb) {
+      s.push(s.pop() + "rotate(" + rb + ")");
+    }
+    if (wa != wb) {
+      q.push({
+        i: s.push(s.pop() + "skewX(", null, ")") - 2,
+        x: d3_interpolateNumber(wa, wb)
+      });
+    } else if (wb) {
+      s.push(s.pop() + "skewX(" + wb + ")");
+    }
+    if (ka[0] != kb[0] || ka[1] != kb[1]) {
+      n = s.push(s.pop() + "scale(", null, ",", null, ")");
+      q.push({
+        i: n - 4,
+        x: d3_interpolateNumber(ka[0], kb[0])
+      }, {
+        i: n - 2,
+        x: d3_interpolateNumber(ka[1], kb[1])
+      });
+    } else if (kb[0] != 1 || kb[1] != 1) {
+      s.push(s.pop() + "scale(" + kb + ")");
+    }
+    n = q.length;
+    return function(t) {
+      var i = -1, o;
+      while (++i < n) s[(o = q[i]).i] = o.x(t);
+      return s.join("");
+    };
+  }
+  function d3_uninterpolateNumber(a, b) {
+    b = b - (a = +a) ? 1 / (b - a) : 0;
+    return function(x) {
+      return (x - a) * b;
+    };
+  }
+  function d3_uninterpolateClamp(a, b) {
+    b = b - (a = +a) ? 1 / (b - a) : 0;
+    return function(x) {
+      return Math.max(0, Math.min(1, (x - a) * b));
+    };
+  }
+  d3.layout = {};
+  d3.layout.bundle = function() {
+    return function(links) {
+      var paths = [], i = -1, n = links.length;
+      while (++i < n) paths.push(d3_layout_bundlePath(links[i]));
+      return paths;
+    };
+  };
+  function d3_layout_bundlePath(link) {
+    var start = link.source, end = link.target, lca = d3_layout_bundleLeastCommonAncestor(start, end), points = [ start ];
+    while (start !== lca) {
+      start = start.parent;
+      points.push(start);
+    }
+    var k = points.length;
+    while (end !== lca) {
+      points.splice(k, 0, end);
+      end = end.parent;
+    }
+    return points;
+  }
+  function d3_layout_bundleAncestors(node) {
+    var ancestors = [], parent = node.parent;
+    while (parent != null) {
+      ancestors.push(node);
+      node = parent;
+      parent = parent.parent;
+    }
+    ancestors.push(node);
+    return ancestors;
+  }
+  function d3_layout_bundleLeastCommonAncestor(a, b) {
+    if (a === b) return a;
+    var aNodes = d3_layout_bundleAncestors(a), bNodes = d3_layout_bundleAncestors(b), aNode = aNodes.pop(), bNode = bNodes.pop(), sharedNode = null;
+    while (aNode === bNode) {
+      sharedNode = aNode;
+      aNode = aNodes.pop();
+      bNode = bNodes.pop();
+    }
+    return sharedNode;
+  }
+  d3.layout.chord = function() {
+    var chord = {}, chords, groups, matrix, n, padding = 0, sortGroups, sortSubgroups, sortChords;
+    function relayout() {
+      var subgroups = {}, groupSums = [], groupIndex = d3.range(n), subgroupIndex = [], k, x, x0, i, j;
+      chords = [];
+      groups = [];
+      k = 0, i = -1;
+      while (++i < n) {
+        x = 0, j = -1;
+        while (++j < n) {
+          x += matrix[i][j];
+        }
+        groupSums.push(x);
+        subgroupIndex.push(d3.range(n));
+        k += x;
+      }
+      if (sortGroups) {
+        groupIndex.sort(function(a, b) {
+          return sortGroups(groupSums[a], groupSums[b]);
+        });
+      }
+      if (sortSubgroups) {
+        subgroupIndex.forEach(function(d, i) {
+          d.sort(function(a, b) {
+            return sortSubgroups(matrix[i][a], matrix[i][b]);
+          });
+        });
+      }
+      k = (τ - padding * n) / k;
+      x = 0, i = -1;
+      while (++i < n) {
+        x0 = x, j = -1;
+        while (++j < n) {
+          var di = groupIndex[i], dj = subgroupIndex[di][j], v = matrix[di][dj], a0 = x, a1 = x += v * k;
+          subgroups[di + "-" + dj] = {
+            index: di,
+            subindex: dj,
+            startAngle: a0,
+            endAngle: a1,
+            value: v
+          };
+        }
+        groups[di] = {
+          index: di,
+          startAngle: x0,
+          endAngle: x,
+          value: (x - x0) / k
+        };
+        x += padding;
+      }
+      i = -1;
+      while (++i < n) {
+        j = i - 1;
+        while (++j < n) {
+          var source = subgroups[i + "-" + j], target = subgroups[j + "-" + i];
+          if (source.value || target.value) {
+            chords.push(source.value < target.value ? {
+              source: target,
+              target: source
+            } : {
+              source: source,
+              target: target
+            });
+          }
+        }
+      }
+      if (sortChords) resort();
+    }
+    function resort() {
+      chords.sort(function(a, b) {
+        return sortChords((a.source.value + a.target.value) / 2, (b.source.value + b.target.value) / 2);
+      });
+    }
+    chord.matrix = function(x) {
+      if (!arguments.length) return matrix;
+      n = (matrix = x) && matrix.length;
+      chords = groups = null;
+      return chord;
+    };
+    chord.padding = function(x) {
+      if (!arguments.length) return padding;
+      padding = x;
+      chords = groups = null;
+      return chord;
+    };
+    chord.sortGroups = function(x) {
+      if (!arguments.length) return sortGroups;
+      sortGroups = x;
+      chords = groups = null;
+      return chord;
+    };
+    chord.sortSubgroups = function(x) {
+      if (!arguments.length) return sortSubgroups;
+      sortSubgroups = x;
+      chords = null;
+      return chord;
+    };
+    chord.sortChords = function(x) {
+      if (!arguments.length) return sortChords;
+      sortChords = x;
+      if (chords) resort();
+      return chord;
+    };
+    chord.chords = function() {
+      if (!chords) relayout();
+      return chords;
+    };
+    chord.groups = function() {
+      if (!groups) relayout();
+      return groups;
+    };
+    return chord;
+  };
+  d3.layout.force = function() {
+    var force = {}, event = d3.dispatch("start", "tick", "end"), size = [ 1, 1 ], drag, alpha, friction = .9, linkDistance = d3_layout_forceLinkDistance, linkStrength = d3_layout_forceLinkStrength, charge = -30, chargeDistance2 = d3_layout_forceChargeDistance2, gravity = .1, theta2 = .64, nodes = [], links = [], distances, strengths, charges;
+    function repulse(node) {
+      return function(quad, x1, _, x2) {
+        if (quad.point !== node) {
+          var dx = quad.cx - node.x, dy = quad.cy - node.y, dw = x2 - x1, dn = dx * dx + dy * dy;
+          if (dw * dw / theta2 < dn) {
+            if (dn < chargeDistance2) {
+              var k = quad.charge / dn;
+              node.px -= dx * k;
+              node.py -= dy * k;
+            }
+            return true;
+          }
+          if (quad.point && dn && dn < chargeDistance2) {
+            var k = quad.pointCharge / dn;
+            node.px -= dx * k;
+            node.py -= dy * k;
+          }
+        }
+        return !quad.charge;
+      };
+    }
+    force.tick = function() {
+      if ((alpha *= .99) < .005) {
+        event.end({
+          type: "end",
+          alpha: alpha = 0
+        });
+        return true;
+      }
+      var n = nodes.length, m = links.length, q, i, o, s, t, l, k, x, y;
+      for (i = 0; i < m; ++i) {
+        o = links[i];
+        s = o.source;
+        t = o.target;
+        x = t.x - s.x;
+        y = t.y - s.y;
+        if (l = x * x + y * y) {
+          l = alpha * strengths[i] * ((l = Math.sqrt(l)) - distances[i]) / l;
+          x *= l;
+          y *= l;
+          t.x -= x * (k = s.weight / (t.weight + s.weight));
+          t.y -= y * k;
+          s.x += x * (k = 1 - k);
+          s.y += y * k;
+        }
+      }
+      if (k = alpha * gravity) {
+        x = size[0] / 2;
+        y = size[1] / 2;
+        i = -1;
+        if (k) while (++i < n) {
+          o = nodes[i];
+          o.x += (x - o.x) * k;
+          o.y += (y - o.y) * k;
+        }
+      }
+      if (charge) {
+        d3_layout_forceAccumulate(q = d3.geom.quadtree(nodes), alpha, charges);
+        i = -1;
+        while (++i < n) {
+          if (!(o = nodes[i]).fixed) {
+            q.visit(repulse(o));
+          }
+        }
+      }
+      i = -1;
+      while (++i < n) {
+        o = nodes[i];
+        if (o.fixed) {
+          o.x = o.px;
+          o.y = o.py;
+        } else {
+          o.x -= (o.px - (o.px = o.x)) * friction;
+          o.y -= (o.py - (o.py = o.y)) * friction;
+        }
+      }
+      event.tick({
+        type: "tick",
+        alpha: alpha
+      });
+    };
+    force.nodes = function(x) {
+      if (!arguments.length) return nodes;
+      nodes = x;
+      return force;
+    };
+    force.links = function(x) {
+      if (!arguments.length) return links;
+      links = x;
+      return force;
+    };
+    force.size = function(x) {
+      if (!arguments.length) return size;
+      size = x;
+      return force;
+    };
+    force.linkDistance = function(x) {
+      if (!arguments.length) return linkDistance;
+      linkDistance = typeof x === "function" ? x : +x;
+      return force;
+    };
+    force.distance = force.linkDistance;
+    force.linkStrength = function(x) {
+      if (!arguments.length) return linkStrength;
+      linkStrength = typeof x === "function" ? x : +x;
+      return force;
+    };
+    force.friction = function(x) {
+      if (!arguments.length) return friction;
+      friction = +x;
+      return force;
+    };
+    force.charge = function(x) {
+      if (!arguments.length) return charge;
+      charge = typeof x === "function" ? x : +x;
+      return force;
+    };
+    force.chargeDistance = function(x) {
+      if (!arguments.length) return Math.sqrt(chargeDistance2);
+      chargeDistance2 = x * x;
+      return force;
+    };
+    force.gravity = function(x) {
+      if (!arguments.length) return gravity;
+      gravity = +x;
+      return force;
+    };
+    force.theta = function(x) {
+      if (!arguments.length) return Math.sqrt(theta2);
+      theta2 = x * x;
+      return force;
+    };
+    force.alpha = function(x) {
+      if (!arguments.length) return alpha;
+      x = +x;
+      if (alpha) {
+        if (x > 0) alpha = x; else alpha = 0;
+      } else if (x > 0) {
+        event.start({
+          type: "start",
+          alpha: alpha = x
+        });
+        d3.timer(force.tick);
+      }
+      return force;
+    };
+    force.start = function() {
+      var i, n = nodes.length, m = links.length, w = size[0], h = size[1], neighbors, o;
+      for (i = 0; i < n; ++i) {
+        (o = nodes[i]).index = i;
+        o.weight = 0;
+      }
+      for (i = 0; i < m; ++i) {
+        o = links[i];
+        if (typeof o.source == "number") o.source = nodes[o.source];
+        if (typeof o.target == "number") o.target = nodes[o.target];
+        ++o.source.weight;
+        ++o.target.weight;
+      }
+      for (i = 0; i < n; ++i) {
+        o = nodes[i];
+        if (isNaN(o.x)) o.x = position("x", w);
+        if (isNaN(o.y)) o.y = position("y", h);
+        if (isNaN(o.px)) o.px = o.x;
+        if (isNaN(o.py)) o.py = o.y;
+      }
+      distances = [];
+      if (typeof linkDistance === "function") for (i = 0; i < m; ++i) distances[i] = +linkDistance.call(this, links[i], i); else for (i = 0; i < m; ++i) distances[i] = linkDistance;
+      strengths = [];
+      if (typeof linkStrength === "function") for (i = 0; i < m; ++i) strengths[i] = +linkStrength.call(this, links[i], i); else for (i = 0; i < m; ++i) strengths[i] = linkStrength;
+      charges = [];
+      if (typeof charge === "function") for (i = 0; i < n; ++i) charges[i] = +charge.call(this, nodes[i], i); else for (i = 0; i < n; ++i) charges[i] = charge;
+      function position(dimension, size) {
+        if (!neighbors) {
+          neighbors = new Array(n);
+          for (j = 0; j < n; ++j) {
+            neighbors[j] = [];
+          }
+          for (j = 0; j < m; ++j) {
+            var o = links[j];
+            neighbors[o.source.index].push(o.target);
+            neighbors[o.target.index].push(o.source);
+          }
+        }
+        var candidates = neighbors[i], j = -1, m = candidates.length, x;
+        while (++j < m) if (!isNaN(x = candidates[j][dimension])) return x;
+        return Math.random() * size;
+      }
+      return force.resume();
+    };
+    force.resume = function() {
+      return force.alpha(.1);
+    };
+    force.stop = function() {
+      return force.alpha(0);
+    };
+    force.drag = function() {
+      if (!drag) drag = d3.behavior.drag().origin(d3_identity).on("dragstart.force", d3_layout_forceDragstart).on("drag.force", dragmove).on("dragend.force", d3_layout_forceDragend);
+      if (!arguments.length) return drag;
+      this.on("mouseover.force", d3_layout_forceMouseover).on("mouseout.force", d3_layout_forceMouseout).call(drag);
+    };
+    function dragmove(d) {
+      d.px = d3.event.x, d.py = d3.event.y;
+      force.resume();
+    }
+    return d3.rebind(force, event, "on");
+  };
+  function d3_layout_forceDragstart(d) {
+    d.fixed |= 2;
+  }
+  function d3_layout_forceDragend(d) {
+    d.fixed &= ~6;
+  }
+  function d3_layout_forceMouseover(d) {
+    d.fixed |= 4;
+    d.px = d.x, d.py = d.y;
+  }
+  function d3_layout_forceMouseout(d) {
+    d.fixed &= ~4;
+  }
+  function d3_layout_forceAccumulate(quad, alpha, charges) {
+    var cx = 0, cy = 0;
+    quad.charge = 0;
+    if (!quad.leaf) {
+      var nodes = quad.nodes, n = nodes.length, i = -1, c;
+      while (++i < n) {
+        c = nodes[i];
+        if (c == null) continue;
+        d3_layout_forceAccumulate(c, alpha, charges);
+        quad.charge += c.charge;
+        cx += c.charge * c.cx;
+        cy += c.charge * c.cy;
+      }
+    }
+    if (quad.point) {
+      if (!quad.leaf) {
+        quad.point.x += Math.random() - .5;
+        quad.point.y += Math.random() - .5;
+      }
+      var k = alpha * charges[quad.point.index];
+      quad.charge += quad.pointCharge = k;
+      cx += k * quad.point.x;
+      cy += k * quad.point.y;
+    }
+    quad.cx = cx / quad.charge;
+    quad.cy = cy / quad.charge;
+  }
+  var d3_layout_forceLinkDistance = 20, d3_layout_forceLinkStrength = 1, d3_layout_forceChargeDistance2 = Infinity;
+  d3.layout.hierarchy = function() {
+    var sort = d3_layout_hierarchySort, children = d3_layout_hierarchyChildren, value = d3_layout_hierarchyValue;
+    function recurse(node, depth, nodes) {
+      var childs = children.call(hierarchy, node, depth);
+      node.depth = depth;
+      nodes.push(node);
+      if (childs && (n = childs.length)) {
+        var i = -1, n, c = node.children = new Array(n), v = 0, j = depth + 1, d;
+        while (++i < n) {
+          d = c[i] = recurse(childs[i], j, nodes);
+          d.parent = node;
+          v += d.value;
+        }
+        if (sort) c.sort(sort);
+        if (value) node.value = v;
+      } else {
+        delete node.children;
+        if (value) {
+          node.value = +value.call(hierarchy, node, depth) || 0;
+        }
+      }
+      return node;
+    }
+    function revalue(node, depth) {
+      var children = node.children, v = 0;
+      if (children && (n = children.length)) {
+        var i = -1, n, j = depth + 1;
+        while (++i < n) v += revalue(children[i], j);
+      } else if (value) {
+        v = +value.call(hierarchy, node, depth) || 0;
+      }
+      if (value) node.value = v;
+      return v;
+    }
+    function hierarchy(d) {
+      var nodes = [];
+      recurse(d, 0, nodes);
+      return nodes;
+    }
+    hierarchy.sort = function(x) {
+      if (!arguments.length) return sort;
+      sort = x;
+      return hierarchy;
+    };
+    hierarchy.children = function(x) {
+      if (!arguments.length) return children;
+      children = x;
+      return hierarchy;
+    };
+    hierarchy.value = function(x) {
+      if (!arguments.length) return value;
+      value = x;
+      return hierarchy;
+    };
+    hierarchy.revalue = function(root) {
+      revalue(root, 0);
+      return root;
+    };
+    return hierarchy;
+  };
+  function d3_layout_hierarchyRebind(object, hierarchy) {
+    d3.rebind(object, hierarchy, "sort", "children", "value");
+    object.nodes = object;
+    object.links = d3_layout_hierarchyLinks;
+    return object;
+  }
+  function d3_layout_hierarchyChildren(d) {
+    return d.children;
+  }
+  function d3_layout_hierarchyValue(d) {
+    return d.value;
+  }
+  function d3_layout_hierarchySort(a, b) {
+    return b.value - a.value;
+  }
+  function d3_layout_hierarchyLinks(nodes) {
+    return d3.merge(nodes.map(function(parent) {
+      return (parent.children || []).map(function(child) {
+        return {
+          source: parent,
+          target: child
+        };
+      });
+    }));
+  }
+  d3.layout.partition = function() {
+    var hierarchy = d3.layout.hierarchy(), size = [ 1, 1 ];
+    function position(node, x, dx, dy) {
+      var children = node.children;
+      node.x = x;
+      node.y = node.depth * dy;
+      node.dx = dx;
+      node.dy = dy;
+      if (children && (n = children.length)) {
+        var i = -1, n, c, d;
+        dx = node.value ? dx / node.value : 0;
+        while (++i < n) {
+          position(c = children[i], x, d = c.value * dx, dy);
+          x += d;
+        }
+      }
+    }
+    function depth(node) {
+      var children = node.children, d = 0;
+      if (children && (n = children.length)) {
+        var i = -1, n;
+        while (++i < n) d = Math.max(d, depth(children[i]));
+      }
+      return 1 + d;
+    }
+    function partition(d, i) {
+      var nodes = hierarchy.call(this, d, i);
+      position(nodes[0], 0, size[0], size[1] / depth(nodes[0]));
+      return nodes;
+    }
+    partition.size = function(x) {
+      if (!arguments.length) return size;
+      size = x;
+      return partition;
+    };
+    return d3_layout_hierarchyRebind(partition, hierarchy);
+  };
+  d3.layout.pie = function() {
+    var value = Number, sort = d3_layout_pieSortByValue, startAngle = 0, endAngle = τ;
+    function pie(data) {
+      var values = data.map(function(d, i) {
+        return +value.call(pie, d, i);
+      });
+      var a = +(typeof startAngle === "function" ? startAngle.apply(this, arguments) : startAngle);
+      var k = ((typeof endAngle === "function" ? endAngle.apply(this, arguments) : endAngle) - a) / d3.sum(values);
+      var index = d3.range(data.length);
+      if (sort != null) index.sort(sort === d3_layout_pieSortByValue ? function(i, j) {
+        return values[j] - values[i];
+      } : function(i, j) {
+        return sort(data[i], data[j]);
+      });
+      var arcs = [];
+      index.forEach(function(i) {
+        var d;
+        arcs[i] = {
+          data: data[i],
+          value: d = values[i],
+          startAngle: a,
+          endAngle: a += d * k
+        };
+      });
+      return arcs;
+    }
+    pie.value = function(x) {
+      if (!arguments.length) return value;
+      value = x;
+      return pie;
+    };
+    pie.sort = function(x) {
+      if (!arguments.length) return sort;
+      sort = x;
+      return pie;
+    };
+    pie.startAngle = function(x) {
+      if (!arguments.length) return startAngle;
+      startAngle = x;
+      return pie;
+    };
+    pie.endAngle = function(x) {
+      if (!arguments.length) return endAngle;
+      endAngle = x;
+      return pie;
+    };
+    return pie;
+  };
+  var d3_layout_pieSortByValue = {};
+  d3.layout.stack = function() {
+    var values = d3_identity, order = d3_layout_stackOrderDefault, offset = d3_layout_stackOffsetZero, out = d3_layout_stackOut, x = d3_layout_stackX, y = d3_layout_stackY;
+    function stack(data, index) {
+      var series = data.map(function(d, i) {
+        return values.call(stack, d, i);
+      });
+      var points = series.map(function(d) {
+        return d.map(function(v, i) {
+          return [ x.call(stack, v, i), y.call(stack, v, i) ];
+        });
+      });
+      var orders = order.call(stack, points, index);
+      series = d3.permute(series, orders);
+      points = d3.permute(points, orders);
+      var offsets = offset.call(stack, points, index);
+      var n = series.length, m = series[0].length, i, j, o;
+      for (j = 0; j < m; ++j) {
+        out.call(stack, series[0][j], o = offsets[j], points[0][j][1]);
+        for (i = 1; i < n; ++i) {
+          out.call(stack, series[i][j], o += points[i - 1][j][1], points[i][j][1]);
+        }
+      }
+      return data;
+    }
+    stack.values = function(x) {
+      if (!arguments.length) return values;
+      values = x;
+      return stack;
+    };
+    stack.order = function(x) {
+      if (!arguments.length) return order;
+      order = typeof x === "function" ? x : d3_layout_stackOrders.get(x) || d3_layout_stackOrderDefault;
+      return stack;
+    };
+    stack.offset = function(x) {
+      if (!arguments.length) return offset;
+      offset = typeof x === "function" ? x : d3_layout_stackOffsets.get(x) || d3_layout_stackOffsetZero;
+      return stack;
+    };
+    stack.x = function(z) {
+      if (!arguments.length) return x;
+      x = z;
+      return stack;
+    };
+    stack.y = function(z) {
+      if (!arguments.length) return y;
+      y = z;
+      return stack;
+    };
+    stack.out = function(z) {
+      if (!arguments.length) return out;
+      out = z;
+      return stack;
+    };
+    return stack;
+  };
+  function d3_layout_stackX(d) {
+    return d.x;
+  }
+  function d3_layout_stackY(d) {
+    return d.y;
+  }
+  function d3_layout_stackOut(d, y0, y) {
+    d.y0 = y0;
+    d.y = y;
+  }
+  var d3_layout_stackOrders = d3.map({
+    "inside-out": function(data) {
+      var n = data.length, i, j, max = data.map(d3_layout_stackMaxIndex), sums = data.map(d3_layout_stackReduceSum), index = d3.range(n).sort(function(a, b) {
+        return max[a] - max[b];
+      }), top = 0, bottom = 0, tops = [], bottoms = [];
+      for (i = 0; i < n; ++i) {
+        j = index[i];
+        if (top < bottom) {
+          top += sums[j];
+          tops.push(j);
+        } else {
+          bottom += sums[j];
+          bottoms.push(j);
+        }
+      }
+      return bottoms.reverse().concat(tops);
+    },
+    reverse: function(data) {
+      return d3.range(data.length).reverse();
+    },
+    "default": d3_layout_stackOrderDefault
+  });
+  var d3_layout_stackOffsets = d3.map({
+    silhouette: function(data) {
+      var n = data.length, m = data[0].length, sums = [], max = 0, i, j, o, y0 = [];
+      for (j = 0; j < m; ++j) {
+        for (i = 0, o = 0; i < n; i++) o += data[i][j][1];
+        if (o > max) max = o;
+        sums.push(o);
+      }
+      for (j = 0; j < m; ++j) {
+        y0[j] = (max - sums[j]) / 2;
+      }
+      return y0;
+    },
+    wiggle: function(data) {
+      var n = data.length, x = data[0], m = x.length, i, j, k, s1, s2, s3, dx, o, o0, y0 = [];
+      y0[0] = o = o0 = 0;
+      for (j = 1; j < m; ++j) {
+        for (i = 0, s1 = 0; i < n; ++i) s1 += data[i][j][1];
+        for (i = 0, s2 = 0, dx = x[j][0] - x[j - 1][0]; i < n; ++i) {
+          for (k = 0, s3 = (data[i][j][1] - data[i][j - 1][1]) / (2 * dx); k < i; ++k) {
+            s3 += (data[k][j][1] - data[k][j - 1][1]) / dx;
+          }
+          s2 += s3 * data[i][j][1];
+        }
+        y0[j] = o -= s1 ? s2 / s1 * dx : 0;
+        if (o < o0) o0 = o;
+      }
+      for (j = 0; j < m; ++j) y0[j] -= o0;
+      return y0;
+    },
+    expand: function(data) {
+      var n = data.length, m = data[0].length, k = 1 / n, i, j, o, y0 = [];
+      for (j = 0; j < m; ++j) {
+        for (i = 0, o = 0; i < n; i++) o += data[i][j][1];
+        if (o) for (i = 0; i < n; i++) data[i][j][1] /= o; else for (i = 0; i < n; i++) data[i][j][1] = k;
+      }
+      for (j = 0; j < m; ++j) y0[j] = 0;
+      return y0;
+    },
+    zero: d3_layout_stackOffsetZero
+  });
+  function d3_layout_stackOrderDefault(data) {
+    return d3.range(data.length);
+  }
+  function d3_layout_stackOffsetZero(data) {
+    var j = -1, m = data[0].length, y0 = [];
+    while (++j < m) y0[j] = 0;
+    return y0;
+  }
+  function d3_layout_stackMaxIndex(array) {
+    var i = 1, j = 0, v = array[0][1], k, n = array.length;
+    for (;i < n; ++i) {
+      if ((k = array[i][1]) > v) {
+        j = i;
+        v = k;
+      }
+    }
+    return j;
+  }
+  function d3_layout_stackReduceSum(d) {
+    return d.reduce(d3_layout_stackSum, 0);
+  }
+  function d3_layout_stackSum(p, d) {
+    return p + d[1];
+  }
+  d3.layout.histogram = function() {
+    var frequency = true, valuer = Number, ranger = d3_layout_histogramRange, binner = d3_layout_histogramBinSturges;
+    function histogram(data, i) {
+      var bins = [], values = data.map(valuer, this), range = ranger.call(this, values, i), thresholds = binner.call(this, range, values, i), bin, i = -1, n = values.length, m = thresholds.length - 1, k = frequency ? 1 : 1 / n, x;
+      while (++i < m) {
+        bin = bins[i] = [];
+        bin.dx = thresholds[i + 1] - (bin.x = thresholds[i]);
+        bin.y = 0;
+      }
+      if (m > 0) {
+        i = -1;
+        while (++i < n) {
+          x = values[i];
+          if (x >= range[0] && x <= range[1]) {
+            bin = bins[d3.bisect(thresholds, x, 1, m) - 1];
+            bin.y += k;
+            bin.push(data[i]);
+          }
+        }
+      }
+      return bins;
+    }
+    histogram.value = function(x) {
+      if (!arguments.length) return valuer;
+      valuer = x;
+      return histogram;
+    };
+    histogram.range = function(x) {
+      if (!arguments.length) return ranger;
+      ranger = d3_functor(x);
+      return histogram;
+    };
+    histogram.bins = function(x) {
+      if (!arguments.length) return binner;
+      binner = typeof x === "number" ? function(range) {
+        return d3_layout_histogramBinFixed(range, x);
+      } : d3_functor(x);
+      return histogram;
+    };
+    histogram.frequency = function(x) {
+      if (!arguments.length) return frequency;
+      frequency = !!x;
+      return histogram;
+    };
+    return histogram;
+  };
+  function d3_layout_histogramBinSturges(range, values) {
+    return d3_layout_histogramBinFixed(range, Math.ceil(Math.log(values.length) / Math.LN2 + 1));
+  }
+  function d3_layout_histogramBinFixed(range, n) {
+    var x = -1, b = +range[0], m = (range[1] - b) / n, f = [];
+    while (++x <= n) f[x] = m * x + b;
+    return f;
+  }
+  function d3_layout_histogramRange(values) {
+    return [ d3.min(values), d3.max(values) ];
+  }
+  d3.layout.tree = function() {
+    var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = false;
+    function tree(d, i) {
+      var nodes = hierarchy.call(this, d, i), root = nodes[0];
+      function firstWalk(node, previousSibling) {
+        var children = node.children, layout = node._tree;
+        if (children && (n = children.length)) {
+          var n, firstChild = children[0], previousChild, ancestor = firstChild, child, i = -1;
+          while (++i < n) {
+            child = children[i];
+            firstWalk(child, previousChild);
+            ancestor = apportion(child, previousChild, ancestor);
+            previousChild = child;
+          }
+          d3_layout_treeShift(node);
+          var midpoint = .5 * (firstChild._tree.prelim + child._tree.prelim);
+          if (previousSibling) {
+            layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling);
+            layout.mod = layout.prelim - midpoint;
+          } else {
+            layout.prelim = midpoint;
+          }
+        } else {
+          if (previousSibling) {
+            layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling);
+          }
+        }
+      }
+      function secondWalk(node, x) {
+        node.x = node._tree.prelim + x;
+        var children = node.children;
+        if (children && (n = children.length)) {
+          var i = -1, n;
+          x += node._tree.mod;
+          while (++i < n) {
+            secondWalk(children[i], x);
+          }
+        }
+      }
+      function apportion(node, previousSibling, ancestor) {
+        if (previousSibling) {
+          var vip = node, vop = node, vim = previousSibling, vom = node.parent.children[0], sip = vip._tree.mod, sop = vop._tree.mod, sim = vim._tree.mod, som = vom._tree.mod, shift;
+          while (vim = d3_layout_treeRight(vim), vip = d3_layout_treeLeft(vip), vim && vip) {
+            vom = d3_layout_treeLeft(vom);
+            vop = d3_layout_treeRight(vop);
+            vop._tree.ancestor = node;
+            shift = vim._tree.prelim + sim - vip._tree.prelim - sip + separation(vim, vip);
+            if (shift > 0) {
+              d3_layout_treeMove(d3_layout_treeAncestor(vim, node, ancestor), node, shift);
+              sip += shift;
+              sop += shift;
+            }
+            sim += vim._tree.mod;
+            sip += vip._tree.mod;
+            som += vom._tree.mod;
+            sop += vop._tree.mod;
+          }
+          if (vim && !d3_layout_treeRight(vop)) {
+            vop._tree.thread = vim;
+            vop._tree.mod += sim - sop;
+          }
+          if (vip && !d3_layout_treeLeft(vom)) {
+            vom._tree.thread = vip;
+            vom._tree.mod += sip - som;
+            ancestor = node;
+          }
+        }
+        return ancestor;
+      }
+      d3_layout_treeVisitAfter(root, function(node, previousSibling) {
+        node._tree = {
+          ancestor: node,
+          prelim: 0,
+          mod: 0,
+          change: 0,
+          shift: 0,
+          number: previousSibling ? previousSibling._tree.number + 1 : 0
+        };
+      });
+      firstWalk(root);
+      secondWalk(root, -root._tree.prelim);
+      var left = d3_layout_treeSearch(root, d3_layout_treeLeftmost), right = d3_layout_treeSearch(root, d3_layout_treeRightmost), deep = d3_layout_treeSearch(root, d3_layout_treeDeepest), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2, y1 = deep.depth || 1;
+      d3_layout_treeVisitAfter(root, nodeSize ? function(node) {
+        node.x *= size[0];
+        node.y = node.depth * size[1];
+        delete node._tree;
+      } : function(node) {
+        node.x = (node.x - x0) / (x1 - x0) * size[0];
+        node.y = node.depth / y1 * size[1];
+        delete node._tree;
+      });
+      return nodes;
+    }
+    tree.separation = function(x) {
+      if (!arguments.length) return separation;
+      separation = x;
+      return tree;
+    };
+    tree.size = function(x) {
+      if (!arguments.length) return nodeSize ? null : size;
+      nodeSize = (size = x) == null;
+      return tree;
+    };
+    tree.nodeSize = function(x) {
+      if (!arguments.length) return nodeSize ? size : null;
+      nodeSize = (size = x) != null;
+      return tree;
+    };
+    return d3_layout_hierarchyRebind(tree, hierarchy);
+  };
+  function d3_layout_treeSeparation(a, b) {
+    return a.parent == b.parent ? 1 : 2;
+  }
+  function d3_layout_treeLeft(node) {
+    var children = node.children;
+    return children && children.length ? children[0] : node._tree.thread;
+  }
+  function d3_layout_treeRight(node) {
+    var children = node.children, n;
+    return children && (n = children.length) ? children[n - 1] : node._tree.thread;
+  }
+  function d3_layout_treeSearch(node, compare) {
+    var children = node.children;
+    if (children && (n = children.length)) {
+      var child, n, i = -1;
+      while (++i < n) {
+        if (compare(child = d3_layout_treeSearch(children[i], compare), node) > 0) {
+          node = child;
+        }
+      }
+    }
+    return node;
+  }
+  function d3_layout_treeRightmost(a, b) {
+    return a.x - b.x;
+  }
+  function d3_layout_treeLeftmost(a, b) {
+    return b.x - a.x;
+  }
+  function d3_layout_treeDeepest(a, b) {
+    return a.depth - b.depth;
+  }
+  function d3_layout_treeVisitAfter(node, callback) {
+    function visit(node, previousSibling) {
+      var children = node.children;
+      if (children && (n = children.length)) {
+        var child, previousChild = null, i = -1, n;
+        while (++i < n) {
+          child = children[i];
+          visit(child, previousChild);
+          previousChild = child;
+        }
+      }
+      callback(node, previousSibling);
+    }
+    visit(node, null);
+  }
+  function d3_layout_treeShift(node) {
+    var shift = 0, change = 0, children = node.children, i = children.length, child;
+    while (--i >= 0) {
+      child = children[i]._tree;
+      child.prelim += shift;
+      child.mod += shift;
+      shift += child.shift + (change += child.change);
+    }
+  }
+  function d3_layout_treeMove(ancestor, node, shift) {
+    ancestor = ancestor._tree;
+    node = node._tree;
+    var change = shift / (node.number - ancestor.number);
+    ancestor.change += change;
+    node.change -= change;
+    node.shift += shift;
+    node.prelim += shift;
+    node.mod += shift;
+  }
+  function d3_layout_treeAncestor(vim, node, ancestor) {
+    return vim._tree.ancestor.parent == node.parent ? vim._tree.ancestor : ancestor;
+  }
+  d3.layout.pack = function() {
+    var hierarchy = d3.layout.hierarchy().sort(d3_layout_packSort), padding = 0, size = [ 1, 1 ], radius;
+    function pack(d, i) {
+      var nodes = hierarchy.call(this, d, i), root = nodes[0], w = size[0], h = size[1], r = radius == null ? Math.sqrt : typeof radius === "function" ? radius : function() {
+        return radius;
+      };
+      root.x = root.y = 0;
+      d3_layout_treeVisitAfter(root, function(d) {
+        d.r = +r(d.value);
+      });
+      d3_layout_treeVisitAfter(root, d3_layout_packSiblings);
+      if (padding) {
+        var dr = padding * (radius ? 1 : Math.max(2 * root.r / w, 2 * root.r / h)) / 2;
+        d3_layout_treeVisitAfter(root, function(d) {
+          d.r += dr;
+        });
+        d3_layout_treeVisitAfter(root, d3_layout_packSiblings);
+        d3_layout_treeVisitAfter(root, function(d) {
+          d.r -= dr;
+        });
+      }
+      d3_layout_packTransform(root, w / 2, h / 2, radius ? 1 : 1 / Math.max(2 * root.r / w, 2 * root.r / h));
+      return nodes;
+    }
+    pack.size = function(_) {
+      if (!arguments.length) return size;
+      size = _;
+      return pack;
+    };
+    pack.radius = function(_) {
+      if (!arguments.length) return radius;
+      radius = _ == null || typeof _ === "function" ? _ : +_;
+      return pack;
+    };
+    pack.padding = function(_) {
+      if (!arguments.length) return padding;
+      padding = +_;
+      return pack;
+    };
+    return d3_layout_hierarchyRebind(pack, hierarchy);
+  };
+  function d3_layout_packSort(a, b) {
+    return a.value - b.value;
+  }
+  function d3_layout_packInsert(a, b) {
+    var c = a._pack_next;
+    a._pack_next = b;
+    b._pack_prev = a;
+    b._pack_next = c;
+    c._pack_prev = b;
+  }
+  function d3_layout_packSplice(a, b) {
+    a._pack_next = b;
+    b._pack_prev = a;
+  }
+  function d3_layout_packIntersects(a, b) {
+    var dx = b.x - a.x, dy = b.y - a.y, dr = a.r + b.r;
+    return .999 * dr * dr > dx * dx + dy * dy;
+  }
+  function d3_layout_packSiblings(node) {
+    if (!(nodes = node.children) || !(n = nodes.length)) return;
+    var nodes, xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity, a, b, c, i, j, k, n;
+    function bound(node) {
+      xMin = Math.min(node.x - node.r, xMin);
+      xMax = Math.max(node.x + node.r, xMax);
+      yMin = Math.min(node.y - node.r, yMin);
+      yMax = Math.max(node.y + node.r, yMax);
+    }
+    nodes.forEach(d3_layout_packLink);
+    a = nodes[0];
+    a.x = -a.r;
+    a.y = 0;
+    bound(a);
+    if (n > 1) {
+      b = nodes[1];
+      b.x = b.r;
+      b.y = 0;
+      bound(b);
+      if (n > 2) {
+        c = nodes[2];
+        d3_layout_packPlace(a, b, c);
+        bound(c);
+        d3_layout_packInsert(a, c);
+        a._pack_prev = c;
+        d3_layout_packInsert(c, b);
+        b = a._pack_next;
+        for (i = 3; i < n; i++) {
+          d3_layout_packPlace(a, b, c = nodes[i]);
+          var isect = 0, s1 = 1, s2 = 1;
+          for (j = b._pack_next; j !== b; j = j._pack_next, s1++) {
+            if (d3_layout_packIntersects(j, c)) {
+              isect = 1;
+              break;
+            }
+          }
+          if (isect == 1) {
+            for (k = a._pack_prev; k !== j._pack_prev; k = k._pack_prev, s2++) {
+              if (d3_layout_packIntersects(k, c)) {
+                break;
+              }
+            }
+          }
+          if (isect) {
+            if (s1 < s2 || s1 == s2 && b.r < a.r) d3_layout_packSplice(a, b = j); else d3_layout_packSplice(a = k, b);
+            i--;
+          } else {
+            d3_layout_packInsert(a, c);
+            b = c;
+            bound(c);
+          }
+        }
+      }
+    }
+    var cx = (xMin + xMax) / 2, cy = (yMin + yMax) / 2, cr = 0;
+    for (i = 0; i < n; i++) {
+      c = nodes[i];
+      c.x -= cx;
+      c.y -= cy;
+      cr = Math.max(cr, c.r + Math.sqrt(c.x * c.x + c.y * c.y));
+    }
+    node.r = cr;
+    nodes.forEach(d3_layout_packUnlink);
+  }
+  function d3_layout_packLink(node) {
+    node._pack_next = node._pack_prev = node;
+  }
+  function d3_layout_packUnlink(node) {
+    delete node._pack_next;
+    delete node._pack_prev;
+  }
+  function d3_layout_packTransform(node, x, y, k) {
+    var children = node.children;
+    node.x = x += k * node.x;
+    node.y = y += k * node.y;
+    node.r *= k;
+    if (children) {
+      var i = -1, n = children.length;
+      while (++i < n) d3_layout_packTransform(children[i], x, y, k);
+    }
+  }
+  function d3_layout_packPlace(a, b, c) {
+    var db = a.r + c.r, dx = b.x - a.x, dy = b.y - a.y;
+    if (db && (dx || dy)) {
+      var da = b.r + c.r, dc = dx * dx + dy * dy;
+      da *= da;
+      db *= db;
+      var x = .5 + (db - da) / (2 * dc), y = Math.sqrt(Math.max(0, 2 * da * (db + dc) - (db -= dc) * db - da * da)) / (2 * dc);
+      c.x = a.x + x * dx + y * dy;
+      c.y = a.y + x * dy - y * dx;
+    } else {
+      c.x = a.x + db;
+      c.y = a.y;
+    }
+  }
+  d3.layout.cluster = function() {
+    var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = false;
+    function cluster(d, i) {
+      var nodes = hierarchy.call(this, d, i), root = nodes[0], previousNode, x = 0;
+      d3_layout_treeVisitAfter(root, function(node) {
+        var children = node.children;
+        if (children && children.length) {
+          node.x = d3_layout_clusterX(children);
+          node.y = d3_layout_clusterY(children);
+        } else {
+          node.x = previousNode ? x += separation(node, previousNode) : 0;
+          node.y = 0;
+          previousNode = node;
+        }
+      });
+      var left = d3_layout_clusterLeft(root), right = d3_layout_clusterRight(root), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2;
+      d3_layout_treeVisitAfter(root, nodeSize ? function(node) {
+        node.x = (node.x - root.x) * size[0];
+        node.y = (root.y - node.y) * size[1];
+      } : function(node) {
+        node.x = (node.x - x0) / (x1 - x0) * size[0];
+        node.y = (1 - (root.y ? node.y / root.y : 1)) * size[1];
+      });
+      return nodes;
+    }
+    cluster.separation = function(x) {
+      if (!arguments.length) return separation;
+      separation = x;
+      return cluster;
+    };
+    cluster.size = function(x) {
+      if (!arguments.length) return nodeSize ? null : size;
+      nodeSize = (size = x) == null;
+      return cluster;
+    };
+    cluster.nodeSize = function(x) {
+      if (!arguments.length) return nodeSize ? size : null;
+      nodeSize = (size = x) != null;
+      return cluster;
+    };
+    return d3_layout_hierarchyRebind(cluster, hierarchy);
+  };
+  function d3_layout_clusterY(children) {
+    return 1 + d3.max(children, function(child) {
+      return child.y;
+    });
+  }
+  function d3_layout_clusterX(children) {
+    return children.reduce(function(x, child) {
+      return x + child.x;
+    }, 0) / children.length;
+  }
+  function d3_layout_clusterLeft(node) {
+    var children = node.children;
+    return children && children.length ? d3_layout_clusterLeft(children[0]) : node;
+  }
+  function d3_layout_clusterRight(node) {
+    var children = node.children, n;
+    return children && (n = children.length) ? d3_layout_clusterRight(children[n - 1]) : node;
+  }
+  d3.layout.treemap = function() {
+    var hierarchy = d3.layout.hierarchy(), round = Math.round, size = [ 1, 1 ], padding = null, pad = d3_layout_treemapPadNull, sticky = false, stickies, mode = "squarify", ratio = .5 * (1 + Math.sqrt(5));
+    function scale(children, k) {
+      var i = -1, n = children.length, child, area;
+      while (++i < n) {
+        area = (child = children[i]).value * (k < 0 ? 0 : k);
+        child.area = isNaN(area) || area <= 0 ? 0 : area;
+      }
+    }
+    function squarify(node) {
+      var children = node.children;
+      if (children && children.length) {
+        var rect = pad(node), row = [], remaining = children.slice(), child, best = Infinity, score, u = mode === "slice" ? rect.dx : mode === "dice" ? rect.dy : mode === "slice-dice" ? node.depth & 1 ? rect.dy : rect.dx : Math.min(rect.dx, rect.dy), n;
+        scale(remaining, rect.dx * rect.dy / node.value);
+        row.area = 0;
+        while ((n = remaining.length) > 0) {
+          row.push(child = remaining[n - 1]);
+          row.area += child.area;
+          if (mode !== "squarify" || (score = worst(row, u)) <= best) {
+            remaining.pop();
+            best = score;
+          } else {
+            row.area -= row.pop().area;
+            position(row, u, rect, false);
+            u = Math.min(rect.dx, rect.dy);
+            row.length = row.area = 0;
+            best = Infinity;
+          }
+        }
+        if (row.length) {
+          position(row, u, rect, true);
+          row.length = row.area = 0;
+        }
+        children.forEach(squarify);
+      }
+    }
+    function stickify(node) {
+      var children = node.children;
+      if (children && children.length) {
+        var rect = pad(node), remaining = children.slice(), child, row = [];
+        scale(remaining, rect.dx * rect.dy / node.value);
+        row.area = 0;
+        while (child = remaining.pop()) {
+          row.push(child);
+          row.area += child.area;
+          if (child.z != null) {
+            position(row, child.z ? rect.dx : rect.dy, rect, !remaining.length);
+            row.length = row.area = 0;
+          }
+        }
+        children.forEach(stickify);
+      }
+    }
+    function worst(row, u) {
+      var s = row.area, r, rmax = 0, rmin = Infinity, i = -1, n = row.length;
+      while (++i < n) {
+        if (!(r = row[i].area)) continue;
+        if (r < rmin) rmin = r;
+        if (r > rmax) rmax = r;
+      }
+      s *= s;
+      u *= u;
+      return s ? Math.max(u * rmax * ratio / s, s / (u * rmin * ratio)) : Infinity;
+    }
+    function position(row, u, rect, flush) {
+      var i = -1, n = row.length, x = rect.x, y = rect.y, v = u ? round(row.area / u) : 0, o;
+      if (u == rect.dx) {
+        if (flush || v > rect.dy) v = rect.dy;
+        while (++i < n) {
+          o = row[i];
+          o.x = x;
+          o.y = y;
+          o.dy = v;
+          x += o.dx = Math.min(rect.x + rect.dx - x, v ? round(o.area / v) : 0);
+        }
+        o.z = true;
+        o.dx += rect.x + rect.dx - x;
+        rect.y += v;
+        rect.dy -= v;
+      } else {
+        if (flush || v > rect.dx) v = rect.dx;
+        while (++i < n) {
+          o = row[i];
+          o.x = x;
+          o.y = y;
+          o.dx = v;
+          y += o.dy = Math.min(rect.y + rect.dy - y, v ? round(o.area / v) : 0);
+        }
+        o.z = false;
+        o.dy += rect.y + rect.dy - y;
+        rect.x += v;
+        rect.dx -= v;
+      }
+    }
+    function treemap(d) {
+      var nodes = stickies || hierarchy(d), root = nodes[0];
+      root.x = 0;
+      root.y = 0;
+      root.dx = size[0];
+      root.dy = size[1];
+      if (stickies) hierarchy.revalue(root);
+      scale([ root ], root.dx * root.dy / root.value);
+      (stickies ? stickify : squarify)(root);
+      if (sticky) stickies = nodes;
+      return nodes;
+    }
+    treemap.size = function(x) {
+      if (!arguments.length) return size;
+      size = x;
+      return treemap;
+    };
+    treemap.padding = function(x) {
+      if (!arguments.length) return padding;
+      function padFunction(node) {
+        var p = x.call(treemap, node, node.depth);
+        return p == null ? d3_layout_treemapPadNull(node) : d3_layout_treemapPad(node, typeof p === "number" ? [ p, p, p, p ] : p);
+      }
+      function padConstant(node) {
+        return d3_layout_treemapPad(node, x);
+      }
+      var type;
+      pad = (padding = x) == null ? d3_layout_treemapPadNull : (type = typeof x) === "function" ? padFunction : type === "number" ? (x = [ x, x, x, x ], 
+      padConstant) : padConstant;
+      return treemap;
+    };
+    treemap.round = function(x) {
+      if (!arguments.length) return round != Number;
+      round = x ? Math.round : Number;
+      return treemap;
+    };
+    treemap.sticky = function(x) {
+      if (!arguments.length) return sticky;
+      sticky = x;
+      stickies = null;
+      return treemap;
+    };
+    treemap.ratio = function(x) {
+      if (!arguments.length) return ratio;
+      ratio = x;
+      return treemap;
+    };
+    treemap.mode = function(x) {
+      if (!arguments.length) return mode;
+      mode = x + "";
+      return treemap;
+    };
+    return d3_layout_hierarchyRebind(treemap, hierarchy);
+  };
+  function d3_layout_treemapPadNull(node) {
+    return {
+      x: node.x,
+      y: node.y,
+      dx: node.dx,
+      dy: node.dy
+    };
+  }
+  function d3_layout_treemapPad(node, padding) {
+    var x = node.x + padding[3], y = node.y + padding[0], dx = node.dx - padding[1] - padding[3], dy = node.dy - padding[0] - padding[2];
+    if (dx < 0) {
+      x += dx / 2;
+      dx = 0;
+    }
+    if (dy < 0) {
+      y += dy / 2;
+      dy = 0;
+    }
+    return {
+      x: x,
+      y: y,
+      dx: dx,
+      dy: dy
+    };
+  }
+  d3.random = {
+    normal: function(µ, σ) {
+      var n = arguments.length;
+      if (n < 2) σ = 1;
+      if (n < 1) µ = 0;
+      return function() {
+        var x, y, r;
+        do {
+          x = Math.random() * 2 - 1;
+          y = Math.random() * 2 - 1;
+          r = x * x + y * y;
+        } while (!r || r > 1);
+        return µ + σ * x * Math.sqrt(-2 * Math.log(r) / r);
+      };
+    },
+    logNormal: function() {
+      var random = d3.random.normal.apply(d3, arguments);
+      return function() {
+        return Math.exp(random());
+      };
+    },
+    bates: function(m) {
+      var random = d3.random.irwinHall(m);
+      return function() {
+        return random() / m;
+      };
+    },
+    irwinHall: function(m) {
+      return function() {
+        for (var s = 0, j = 0; j < m; j++) s += Math.random();
+        return s;
+      };
+    }
+  };
+  d3.scale = {};
+  function d3_scaleExtent(domain) {
+    var start = domain[0], stop = domain[domain.length - 1];
+    return start < stop ? [ start, stop ] : [ stop, start ];
+  }
+  function d3_scaleRange(scale) {
+    return scale.rangeExtent ? scale.rangeExtent() : d3_scaleExtent(scale.range());
+  }
+  function d3_scale_bilinear(domain, range, uninterpolate, interpolate) {
+    var u = uninterpolate(domain[0], domain[1]), i = interpolate(range[0], range[1]);
+    return function(x) {
+      return i(u(x));
+    };
+  }
+  function d3_scale_nice(domain, nice) {
+    var i0 = 0, i1 = domain.length - 1, x0 = domain[i0], x1 = domain[i1], dx;
+    if (x1 < x0) {
+      dx = i0, i0 = i1, i1 = dx;
+      dx = x0, x0 = x1, x1 = dx;
+    }
+    domain[i0] = nice.floor(x0);
+    domain[i1] = nice.ceil(x1);
+    return domain;
+  }
+  function d3_scale_niceStep(step) {
+    return step ? {
+      floor: function(x) {
+        return Math.floor(x / step) * step;
+      },
+      ceil: function(x) {
+        return Math.ceil(x / step) * step;
+      }
+    } : d3_scale_niceIdentity;
+  }
+  var d3_scale_niceIdentity = {
+    floor: d3_identity,
+    ceil: d3_identity
+  };
+  function d3_scale_polylinear(domain, range, uninterpolate, interpolate) {
+    var u = [], i = [], j = 0, k = Math.min(domain.length, range.length) - 1;
+    if (domain[k] < domain[0]) {
+      domain = domain.slice().reverse();
+      range = range.slice().reverse();
+    }
+    while (++j <= k) {
+      u.push(uninterpolate(domain[j - 1], domain[j]));
+      i.push(interpolate(range[j - 1], range[j]));
+    }
+    return function(x) {
+      var j = d3.bisect(domain, x, 1, k) - 1;
+      return i[j](u[j](x));
+    };
+  }
+  d3.scale.linear = function() {
+    return d3_scale_linear([ 0, 1 ], [ 0, 1 ], d3_interpolate, false);
+  };
+  function d3_scale_linear(domain, range, interpolate, clamp) {
+    var output, input;
+    function rescale() {
+      var linear = Math.min(domain.length, range.length) > 2 ? d3_scale_polylinear : d3_scale_bilinear, uninterpolate = clamp ? d3_uninterpolateClamp : d3_uninterpolateNumber;
+      output = linear(domain, range, uninterpolate, interpolate);
+      input = linear(range, domain, uninterpolate, d3_interpolate);
+      return scale;
+    }
+    function scale(x) {
+      return output(x);
+    }
+    scale.invert = function(y) {
+      return input(y);
+    };
+    scale.domain = function(x) {
+      if (!arguments.length) return domain;
+      domain = x.map(Number);
+      return rescale();
+    };
+    scale.range = function(x) {
+      if (!arguments.length) return range;
+      range = x;
+      return rescale();
+    };
+    scale.rangeRound = function(x) {
+      return scale.range(x).interpolate(d3_interpolateRound);
+    };
+    scale.clamp = function(x) {
+      if (!arguments.length) return clamp;
+      clamp = x;
+      return rescale();
+    };
+    scale.interpolate = function(x) {
+      if (!arguments.length) return interpolate;
+      interpolate = x;
+      return rescale();
+    };
+    scale.ticks = function(m) {
+      return d3_scale_linearTicks(domain, m);
+    };
+    scale.tickFormat = function(m, format) {
+      return d3_scale_linearTickFormat(domain, m, format);
+    };
+    scale.nice = function(m) {
+      d3_scale_linearNice(domain, m);
+      return rescale();
+    };
+    scale.copy = function() {
+      return d3_scale_linear(domain, range, interpolate, clamp);
+    };
+    return rescale();
+  }
+  function d3_scale_linearRebind(scale, linear) {
+    return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp");
+  }
+  function d3_scale_linearNice(domain, m) {
+    return d3_scale_nice(domain, d3_scale_niceStep(d3_scale_linearTickRange(domain, m)[2]));
+  }
+  function d3_scale_linearTickRange(domain, m) {
+    if (m == null) m = 10;
+    var extent = d3_scaleExtent(domain), span = extent[1] - extent[0], step = Math.pow(10, Math.floor(Math.log(span / m) / Math.LN10)), err = m / span * step;
+    if (err <= .15) step *= 10; else if (err <= .35) step *= 5; else if (err <= .75) step *= 2;
+    extent[0] = Math.ceil(extent[0] / step) * step;
+    extent[1] = Math.floor(extent[1] / step) * step + step * .5;
+    extent[2] = step;
+    return extent;
+  }
+  function d3_scale_linearTicks(domain, m) {
+    return d3.range.apply(d3, d3_scale_linearTickRange(domain, m));
+  }
+  function d3_scale_linearTickFormat(domain, m, format) {
+    var range = d3_scale_linearTickRange(domain, m);
+    if (format) {
+      var match = d3_format_re.exec(format);
+      match.shift();
+      if (match[8] === "s") {
+        var prefix = d3.formatPrefix(Math.max(abs(range[0]), abs(range[1])));
+        if (!match[7]) match[7] = "." + d3_scale_linearPrecision(prefix.scale(range[2]));
+        match[8] = "f";
+        format = d3.format(match.join(""));
+        return function(d) {
+          return format(prefix.scale(d)) + prefix.symbol;
+        };
+      }
+      if (!match[7]) match[7] = "." + d3_scale_linearFormatPrecision(match[8], range);
+      format = match.join("");
+    } else {
+      format = ",." + d3_scale_linearPrecision(range[2]) + "f";
+    }
+    return d3.format(format);
+  }
+  var d3_scale_linearFormatSignificant = {
+    s: 1,
+    g: 1,
+    p: 1,
+    r: 1,
+    e: 1
+  };
+  function d3_scale_linearPrecision(value) {
+    return -Math.floor(Math.log(value) / Math.LN10 + .01);
+  }
+  function d3_scale_linearFormatPrecision(type, range) {
+    var p = d3_scale_linearPrecision(range[2]);
+    return type in d3_scale_linearFormatSignificant ? Math.abs(p - d3_scale_linearPrecision(Math.max(abs(range[0]), abs(range[1])))) + +(type !== "e") : p - (type === "%") * 2;
+  }
+  d3.scale.log = function() {
+    return d3_scale_log(d3.scale.linear().domain([ 0, 1 ]), 10, true, [ 1, 10 ]);
+  };
+  function d3_scale_log(linear, base, positive, domain) {
+    function log(x) {
+      return (positive ? Math.log(x < 0 ? 0 : x) : -Math.log(x > 0 ? 0 : -x)) / Math.log(base);
+    }
+    function pow(x) {
+      return positive ? Math.pow(base, x) : -Math.pow(base, -x);
+    }
+    function scale(x) {
+      return linear(log(x));
+    }
+    scale.invert = function(x) {
+      return pow(linear.invert(x));
+    };
+    scale.domain = function(x) {
+      if (!arguments.length) return domain;
+      positive = x[0] >= 0;
+      linear.domain((domain = x.map(Number)).map(log));
+      return scale;
+    };
+    scale.base = function(_) {
+      if (!arguments.length) return base;
+      base = +_;
+      linear.domain(domain.map(log));
+      return scale;
+    };
+    scale.nice = function() {
+      var niced = d3_scale_nice(domain.map(log), positive ? Math : d3_scale_logNiceNegative);
+      linear.domain(niced);
+      domain = niced.map(pow);
+      return scale;
+    };
+    scale.ticks = function() {
+      var extent = d3_scaleExtent(domain), ticks = [], u = extent[0], v = extent[1], i = Math.floor(log(u)), j = Math.ceil(log(v)), n = base % 1 ? 2 : base;
+      if (isFinite(j - i)) {
+        if (positive) {
+          for (;i < j; i++) for (var k = 1; k < n; k++) ticks.push(pow(i) * k);
+          ticks.push(pow(i));
+        } else {
+          ticks.push(pow(i));
+          for (;i++ < j; ) for (var k = n - 1; k > 0; k--) ticks.push(pow(i) * k);
+        }
+        for (i = 0; ticks[i] < u; i++) {}
+        for (j = ticks.length; ticks[j - 1] > v; j--) {}
+        ticks = ticks.slice(i, j);
+      }
+      return ticks;
+    };
+    scale.tickFormat = function(n, format) {
+      if (!arguments.length) return d3_scale_logFormat;
+      if (arguments.length < 2) format = d3_scale_logFormat; else if (typeof format !== "function") format = d3.format(format);
+      var k = Math.max(.1, n / scale.ticks().length), f = positive ? (e = 1e-12, Math.ceil) : (e = -1e-12, 
+      Math.floor), e;
+      return function(d) {
+        return d / pow(f(log(d) + e)) <= k ? format(d) : "";
+      };
+    };
+    scale.copy = function() {
+      return d3_scale_log(linear.copy(), base, positive, domain);
+    };
+    return d3_scale_linearRebind(scale, linear);
+  }
+  var d3_scale_logFormat = d3.format(".0e"), d3_scale_logNiceNegative = {
+    floor: function(x) {
+      return -Math.ceil(-x);
+    },
+    ceil: function(x) {
+      return -Math.floor(-x);
+    }
+  };
+  d3.scale.pow = function() {
+    return d3_scale_pow(d3.scale.linear(), 1, [ 0, 1 ]);
+  };
+  function d3_scale_pow(linear, exponent, domain) {
+    var powp = d3_scale_powPow(exponent), powb = d3_scale_powPow(1 / exponent);
+    function scale(x) {
+      return linear(powp(x));
+    }
+    scale.invert = function(x) {
+      return powb(linear.invert(x));
+    };
+    scale.domain = function(x) {
+      if (!arguments.length) return domain;
+      linear.domain((domain = x.map(Number)).map(powp));
+      return scale;
+    };
+    scale.ticks = function(m) {
+      return d3_scale_linearTicks(domain, m);
+    };
+    scale.tickFormat = function(m, format) {
+      return d3_scale_linearTickFormat(domain, m, format);
+    };
+    scale.nice = function(m) {
+      return scale.domain(d3_scale_linearNice(domain, m));
+    };
+    scale.exponent = function(x) {
+      if (!arguments.length) return exponent;
+      powp = d3_scale_powPow(exponent = x);
+      powb = d3_scale_powPow(1 / exponent);
+      linear.domain(domain.map(powp));
+      return scale;
+    };
+    scale.copy = function() {
+      return d3_scale_pow(linear.copy(), exponent, domain);
+    };
+    return d3_scale_linearRebind(scale, linear);
+  }
+  function d3_scale_powPow(e) {
+    return function(x) {
+      return x < 0 ? -Math.pow(-x, e) : Math.pow(x, e);
+    };
+  }
+  d3.scale.sqrt = function() {
+    return d3.scale.pow().exponent(.5);
+  };
+  d3.scale.ordinal = function() {
+    return d3_scale_ordinal([], {
+      t: "range",
+      a: [ [] ]
+    });
+  };
+  function d3_scale_ordinal(domain, ranger) {
+    var index, range, rangeBand;
+    function scale(x) {
+      return range[((index.get(x) || (ranger.t === "range" ? index.set(x, domain.push(x)) : NaN)) - 1) % range.length];
+    }
+    function steps(start, step) {
+      return d3.range(domain.length).map(function(i) {
+        return start + step * i;
+      });
+    }
+    scale.domain = function(x) {
+      if (!arguments.length) return domain;
+      domain = [];
+      index = new d3_Map();
+      var i = -1, n = x.length, xi;
+      while (++i < n) if (!index.has(xi = x[i])) index.set(xi, domain.push(xi));
+      return scale[ranger.t].apply(scale, ranger.a);
+    };
+    scale.range = function(x) {
+      if (!arguments.length) return range;
+      range = x;
+      rangeBand = 0;
+      ranger = {
+        t: "range",
+        a: arguments
+      };
+      return scale;
+    };
+    scale.rangePoints = function(x, padding) {
+      if (arguments.length < 2) padding = 0;
+      var start = x[0], stop = x[1], step = (stop - start) / (Math.max(1, domain.length - 1) + padding);
+      range = steps(domain.length < 2 ? (start + stop) / 2 : start + step * padding / 2, step);
+      rangeBand = 0;
+      ranger = {
+        t: "rangePoints",
+        a: arguments
+      };
+      return scale;
+    };
+    scale.rangeBands = function(x, padding, outerPadding) {
+      if (arguments.length < 2) padding = 0;
+      if (arguments.length < 3) outerPadding = padding;
+      var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = (stop - start) / (domain.length - padding + 2 * outerPadding);
+      range = steps(start + step * outerPadding, step);
+      if (reverse) range.reverse();
+      rangeBand = step * (1 - padding);
+      ranger = {
+        t: "rangeBands",
+        a: arguments
+      };
+      return scale;
+    };
+    scale.rangeRoundBands = function(x, padding, outerPadding) {
+      if (arguments.length < 2) padding = 0;
+      if (arguments.length < 3) outerPadding = padding;
+      var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = Math.floor((stop - start) / (domain.length - padding + 2 * outerPadding)), error = stop - start - (domain.length - padding) * step;
+      range = steps(start + Math.round(error / 2), step);
+      if (reverse) range.reverse();
+      rangeBand = Math.round(step * (1 - padding));
+      ranger = {
+        t: "rangeRoundBands",
+        a: arguments
+      };
+      return scale;
+    };
+    scale.rangeBand = function() {
+      return rangeBand;
+    };
+    scale.rangeExtent = function() {
+      return d3_scaleExtent(ranger.a[0]);
+    };
+    scale.copy = function() {
+      return d3_scale_ordinal(domain, ranger);
+    };
+    return scale.domain(domain);
+  }
+  d3.scale.category10 = function() {
+    return d3.scale.ordinal().range(d3_category10);
+  };
+  d3.scale.category20 = function() {
+    return d3.scale.ordinal().range(d3_category20);
+  };
+  d3.scale.category20b = function() {
+    return d3.scale.ordinal().range(d3_category20b);
+  };
+  d3.scale.category20c = function() {
+    return d3.scale.ordinal().range(d3_category20c);
+  };
+  var d3_category10 = [ 2062260, 16744206, 2924588, 14034728, 9725885, 9197131, 14907330, 8355711, 12369186, 1556175 ].map(d3_rgbString);
+  var d3_category20 = [ 2062260, 11454440, 16744206, 16759672, 2924588, 10018698, 14034728, 16750742, 9725885, 12955861, 9197131, 12885140, 14907330, 16234194, 8355711, 13092807, 12369186, 14408589, 1556175, 10410725 ].map(d3_rgbString);
+  var d3_category20b = [ 3750777, 5395619, 7040719, 10264286, 6519097, 9216594, 11915115, 13556636, 9202993, 12426809, 15186514, 15190932, 8666169, 11356490, 14049643, 15177372, 8077683, 10834324, 13528509, 14589654 ].map(d3_rgbString);
+  var d3_category20c = [ 3244733, 7057110, 10406625, 13032431, 15095053, 16616764, 16625259, 16634018, 3253076, 7652470, 10607003, 13101504, 7695281, 10394312, 12369372, 14342891, 6513507, 9868950, 12434877, 14277081 ].map(d3_rgbString);
+  d3.scale.quantile = function() {
+    return d3_scale_quantile([], []);
+  };
+  function d3_scale_quantile(domain, range) {
+    var thresholds;
+    function rescale() {
+      var k = 0, q = range.length;
+      thresholds = [];
+      while (++k < q) thresholds[k - 1] = d3.quantile(domain, k / q);
+      return scale;
+    }
+    function scale(x) {
+      if (!isNaN(x = +x)) return range[d3.bisect(thresholds, x)];
+    }
+    scale.domain = function(x) {
+      if (!arguments.length) return domain;
+      domain = x.filter(function(d) {
+        return !isNaN(d);
+      }).sort(d3_ascending);
+      return rescale();
+    };
+    scale.range = function(x) {
+      if (!arguments.length) return range;
+      range = x;
+      return rescale();
+    };
+    scale.quantiles = function() {
+      return thresholds;
+    };
+    scale.invertExtent = function(y) {
+      y = range.indexOf(y);
+      return y < 0 ? [ NaN, NaN ] : [ y > 0 ? thresholds[y - 1] : domain[0], y < thresholds.length ? thresholds[y] : domain[domain.length - 1] ];
+    };
+    scale.copy = function() {
+      return d3_scale_quantile(domain, range);
+    };
+    return rescale();
+  }
+  d3.scale.quantize = function() {
+    return d3_scale_quantize(0, 1, [ 0, 1 ]);
+  };
+  function d3_scale_quantize(x0, x1, range) {
+    var kx, i;
+    function scale(x) {
+      return range[Math.max(0, Math.min(i, Math.floor(kx * (x - x0))))];
+    }
+    function rescale() {
+      kx = range.length / (x1 - x0);
+      i = range.length - 1;
+      return scale;
+    }
+    scale.domain = function(x) {
+      if (!arguments.length) return [ x0, x1 ];
+      x0 = +x[0];
+      x1 = +x[x.length - 1];
+      return rescale();
+    };
+    scale.range = function(x) {
+      if (!arguments.length) return range;
+      range = x;
+      return rescale();
+    };
+    scale.invertExtent = function(y) {
+      y = range.indexOf(y);
+      y = y < 0 ? NaN : y / kx + x0;
+      return [ y, y + 1 / kx ];
+    };
+    scale.copy = function() {
+      return d3_scale_quantize(x0, x1, range);
+    };
+    return rescale();
+  }
+  d3.scale.threshold = function() {
+    return d3_scale_threshold([ .5 ], [ 0, 1 ]);
+  };
+  function d3_scale_threshold(domain, range) {
+    function scale(x) {
+      if (x <= x) return range[d3.bisect(domain, x)];
+    }
+    scale.domain = function(_) {
+      if (!arguments.length) return domain;
+      domain = _;
+      return scale;
+    };
+    scale.range = function(_) {
+      if (!arguments.length) return range;
+      range = _;
+      return scale;
+    };
+    scale.invertExtent = function(y) {
+      y = range.indexOf(y);
+      return [ domain[y - 1], domain[y] ];
+    };
+    scale.copy = function() {
+      return d3_scale_threshold(domain, range);
+    };
+    return scale;
+  }
+  d3.scale.identity = function() {
+    return d3_scale_identity([ 0, 1 ]);
+  };
+  function d3_scale_identity(domain) {
+    function identity(x) {
+      return +x;
+    }
+    identity.invert = identity;
+    identity.domain = identity.range = function(x) {
+      if (!arguments.length) return domain;
+      domain = x.map(identity);
+      return identity;
+    };
+    identity.ticks = function(m) {
+      return d3_scale_linearTicks(domain, m);
+    };
+    identity.tickFormat = function(m, format) {
+      return d3_scale_linearTickFormat(domain, m, format);
+    };
+    identity.copy = function() {
+      return d3_scale_identity(domain);
+    };
+    return identity;
+  }
+  d3.svg = {};
+  d3.svg.arc = function() {
+    var innerRadius = d3_svg_arcInnerRadius, outerRadius = d3_svg_arcOuterRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle;
+    function arc() {
+      var r0 = innerRadius.apply(this, arguments), r1 = outerRadius.apply(this, arguments), a0 = startAngle.apply(this, arguments) + d3_svg_arcOffset, a1 = endAngle.apply(this, arguments) + d3_svg_arcOffset, da = (a1 < a0 && (da = a0, 
+      a0 = a1, a1 = da), a1 - a0), df = da < π ? "0" : "1", c0 = Math.cos(a0), s0 = Math.sin(a0), c1 = Math.cos(a1), s1 = Math.sin(a1);
+      return da >= d3_svg_arcMax ? r0 ? "M0," + r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 + "M0," + r0 + "A" + r0 + "," + r0 + " 0 1,0 0," + -r0 + "A" + r0 + "," + r0 + " 0 1,0 0," + r0 + "Z" : "M0," + r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 + "Z" : r0 ? "M" + r1 * c0 + "," + r1 * s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 + "L" + r0 * c1 + "," + r0 * s1 + "A" + r0 + "," + r0 + " 0 " + df + ",0 " + r0 * c0 + "," + r0 * s0 + "Z" : "M" + r1 * c0 + "," + r1 * s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 + "L0,0" + "Z";
+    }
+    arc.innerRadius = function(v) {
+      if (!arguments.length) return innerRadius;
+      innerRadius = d3_functor(v);
+      return arc;
+    };
+    arc.outerRadius = function(v) {
+      if (!arguments.length) return outerRadius;
+      outerRadius = d3_functor(v);
+      return arc;
+    };
+    arc.startAngle = function(v) {
+      if (!arguments.length) return startAngle;
+      startAngle = d3_functor(v);
+      return arc;
+    };
+    arc.endAngle = function(v) {
+      if (!arguments.length) return endAngle;
+      endAngle = d3_functor(v);
+      return arc;
+    };
+    arc.centroid = function() {
+      var r = (innerRadius.apply(this, arguments) + outerRadius.apply(this, arguments)) / 2, a = (startAngle.apply(this, arguments) + endAngle.apply(this, arguments)) / 2 + d3_svg_arcOffset;
+      return [ Math.cos(a) * r, Math.sin(a) * r ];
+    };
+    return arc;
+  };
+  var d3_svg_arcOffset = -halfπ, d3_svg_arcMax = τ - ε;
+  function d3_svg_arcInnerRadius(d) {
+    return d.innerRadius;
+  }
+  function d3_svg_arcOuterRadius(d) {
+    return d.outerRadius;
+  }
+  function d3_svg_arcStartAngle(d) {
+    return d.startAngle;
+  }
+  function d3_svg_arcEndAngle(d) {
+    return d.endAngle;
+  }
+  function d3_svg_line(projection) {
+    var x = d3_geom_pointX, y = d3_geom_pointY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, tension = .7;
+    function line(data) {
+      var segments = [], points = [], i = -1, n = data.length, d, fx = d3_functor(x), fy = d3_functor(y);
+      function segment() {
+        segments.push("M", interpolate(projection(points), tension));
+      }
+      while (++i < n) {
+        if (defined.call(this, d = data[i], i)) {
+          points.push([ +fx.call(this, d, i), +fy.call(this, d, i) ]);
+        } else if (points.length) {
+          segment();
+          points = [];
+        }
+      }
+      if (points.length) segment();
+      return segments.length ? segments.join("") : null;
+    }
+    line.x = function(_) {
+      if (!arguments.length) return x;
+      x = _;
+      return line;
+    };
+    line.y = function(_) {
+      if (!arguments.length) return y;
+      y = _;
+      return line;
+    };
+    line.defined = function(_) {
+      if (!arguments.length) return defined;
+      defined = _;
+      return line;
+    };
+    line.interpolate = function(_) {
+      if (!arguments.length) return interpolateKey;
+      if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key;
+      return line;
+    };
+    line.tension = function(_) {
+      if (!arguments.length) return tension;
+      tension = _;
+      return line;
+    };
+    return line;
+  }
+  d3.svg.line = function() {
+    return d3_svg_line(d3_identity);
+  };
+  var d3_svg_lineInterpolators = d3.map({
+    linear: d3_svg_lineLinear,
+    "linear-closed": d3_svg_lineLinearClosed,
+    step: d3_svg_lineStep,
+    "step-before": d3_svg_lineStepBefore,
+    "step-after": d3_svg_lineStepAfter,
+    basis: d3_svg_lineBasis,
+    "basis-open": d3_svg_lineBasisOpen,
+    "basis-closed": d3_svg_lineBasisClosed,
+    bundle: d3_svg_lineBundle,
+    cardinal: d3_svg_lineCardinal,
+    "cardinal-open": d3_svg_lineCardinalOpen,
+    "cardinal-closed": d3_svg_lineCardinalClosed,
+    monotone: d3_svg_lineMonotone
+  });
+  d3_svg_lineInterpolators.forEach(function(key, value) {
+    value.key = key;
+    value.closed = /-closed$/.test(key);
+  });
+  function d3_svg_lineLinear(points) {
+    return points.join("L");
+  }
+  function d3_svg_lineLinearClosed(points) {
+    return d3_svg_lineLinear(points) + "Z";
+  }
+  function d3_svg_lineStep(points) {
+    var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ];
+    while (++i < n) path.push("H", (p[0] + (p = points[i])[0]) / 2, "V", p[1]);
+    if (n > 1) path.push("H", p[0]);
+    return path.join("");
+  }
+  function d3_svg_lineStepBefore(points) {
+    var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ];
+    while (++i < n) path.push("V", (p = points[i])[1], "H", p[0]);
+    return path.join("");
+  }
+  function d3_svg_lineStepAfter(points) {
+    var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ];
+    while (++i < n) path.push("H", (p = points[i])[0], "V", p[1]);
+    return path.join("");
+  }
+  function d3_svg_lineCardinalOpen(points, tension) {
+    return points.length < 4 ? d3_svg_lineLinear(points) : points[1] + d3_svg_lineHermite(points.slice(1, points.length - 1), d3_svg_lineCardinalTangents(points, tension));
+  }
+  function d3_svg_lineCardinalClosed(points, tension) {
+    return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite((points.push(points[0]), 
+    points), d3_svg_lineCardinalTangents([ points[points.length - 2] ].concat(points, [ points[1] ]), tension));
+  }
+  function d3_svg_lineCardinal(points, tension) {
+    return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineCardinalTangents(points, tension));
+  }
+  function d3_svg_lineHermite(points, tangents) {
+    if (tangents.length < 1 || points.length != tangents.length && points.length != tangents.length + 2) {
+      return d3_svg_lineLinear(points);
+    }
+    var quad = points.length != tangents.length, path = "", p0 = points[0], p = points[1], t0 = tangents[0], t = t0, pi = 1;
+    if (quad) {
+      path += "Q" + (p[0] - t0[0] * 2 / 3) + "," + (p[1] - t0[1] * 2 / 3) + "," + p[0] + "," + p[1];
+      p0 = points[1];
+      pi = 2;
+    }
+    if (tangents.length > 1) {
+      t = tangents[1];
+      p = points[pi];
+      pi++;
+      path += "C" + (p0[0] + t0[0]) + "," + (p0[1] + t0[1]) + "," + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1];
+      for (var i = 2; i < tangents.length; i++, pi++) {
+        p = points[pi];
+        t = tangents[i];
+        path += "S" + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1];
+      }
+    }
+    if (quad) {
+      var lp = points[pi];
+      path += "Q" + (p[0] + t[0] * 2 / 3) + "," + (p[1] + t[1] * 2 / 3) + "," + lp[0] + "," + lp[1];
+    }
+    return path;
+  }
+  function d3_svg_lineCardinalTangents(points, tension) {
+    var tangents = [], a = (1 - tension) / 2, p0, p1 = points[0], p2 = points[1], i = 1, n = points.length;
+    while (++i < n) {
+      p0 = p1;
+      p1 = p2;
+      p2 = points[i];
+      tangents.push([ a * (p2[0] - p0[0]), a * (p2[1] - p0[1]) ]);
+    }
+    return tangents;
+  }
+  function d3_svg_lineBasis(points) {
+    if (points.length < 3) return d3_svg_lineLinear(points);
+    var i = 1, n = points.length, pi = points[0], x0 = pi[0], y0 = pi[1], px = [ x0, x0, x0, (pi = points[1])[0] ], py = [ y0, y0, y0, pi[1] ], path = [ x0, ",", y0, "L", d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ];
+    points.push(points[n - 1]);
+    while (++i <= n) {
+      pi = points[i];
+      px.shift();
+      px.push(pi[0]);
+      py.shift();
+      py.push(pi[1]);
+      d3_svg_lineBasisBezier(path, px, py);
+    }
+    points.pop();
+    path.push("L", pi);
+    return path.join("");
+  }
+  function d3_svg_lineBasisOpen(points) {
+    if (points.length < 4) return d3_svg_lineLinear(points);
+    var path = [], i = -1, n = points.length, pi, px = [ 0 ], py = [ 0 ];
+    while (++i < 3) {
+      pi = points[i];
+      px.push(pi[0]);
+      py.push(pi[1]);
+    }
+    path.push(d3_svg_lineDot4(d3_svg_lineBasisBezier3, px) + "," + d3_svg_lineDot4(d3_svg_lineBasisBezier3, py));
+    --i;
+    while (++i < n) {
+      pi = points[i];
+      px.shift();
+      px.push(pi[0]);
+      py.shift();
+      py.push(pi[1]);
+      d3_svg_lineBasisBezier(path, px, py);
+    }
+    return path.join("");
+  }
+  function d3_svg_lineBasisClosed(points) {
+    var path, i = -1, n = points.length, m = n + 4, pi, px = [], py = [];
+    while (++i < 4) {
+      pi = points[i % n];
+      px.push(pi[0]);
+      py.push(pi[1]);
+    }
+    path = [ d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ];
+    --i;
+    while (++i < m) {
+      pi = points[i % n];
+      px.shift();
+      px.push(pi[0]);
+      py.shift();
+      py.push(pi[1]);
+      d3_svg_lineBasisBezier(path, px, py);
+    }
+    return path.join("");
+  }
+  function d3_svg_lineBundle(points, tension) {
+    var n = points.length - 1;
+    if (n) {
+      var x0 = points[0][0], y0 = points[0][1], dx = points[n][0] - x0, dy = points[n][1] - y0, i = -1, p, t;
+      while (++i <= n) {
+        p = points[i];
+        t = i / n;
+        p[0] = tension * p[0] + (1 - tension) * (x0 + t * dx);
+        p[1] = tension * p[1] + (1 - tension) * (y0 + t * dy);
+      }
+    }
+    return d3_svg_lineBasis(points);
+  }
+  function d3_svg_lineDot4(a, b) {
+    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
+  }
+  var d3_svg_lineBasisBezier1 = [ 0, 2 / 3, 1 / 3, 0 ], d3_svg_lineBasisBezier2 = [ 0, 1 / 3, 2 / 3, 0 ], d3_svg_lineBasisBezier3 = [ 0, 1 / 6, 2 / 3, 1 / 6 ];
+  function d3_svg_lineBasisBezier(path, x, y) {
+    path.push("C", d3_svg_lineDot4(d3_svg_lineBasisBezier1, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier1, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, y));
+  }
+  function d3_svg_lineSlope(p0, p1) {
+    return (p1[1] - p0[1]) / (p1[0] - p0[0]);
+  }
+  function d3_svg_lineFiniteDifferences(points) {
+    var i = 0, j = points.length - 1, m = [], p0 = points[0], p1 = points[1], d = m[0] = d3_svg_lineSlope(p0, p1);
+    while (++i < j) {
+      m[i] = (d + (d = d3_svg_lineSlope(p0 = p1, p1 = points[i + 1]))) / 2;
+    }
+    m[i] = d;
+    return m;
+  }
+  function d3_svg_lineMonotoneTangents(points) {
+    var tangents = [], d, a, b, s, m = d3_svg_lineFiniteDifferences(points), i = -1, j = points.length - 1;
+    while (++i < j) {
+      d = d3_svg_lineSlope(points[i], points[i + 1]);
+      if (abs(d) < ε) {
+        m[i] = m[i + 1] = 0;
+      } else {
+        a = m[i] / d;
+        b = m[i + 1] / d;
+        s = a * a + b * b;
+        if (s > 9) {
+          s = d * 3 / Math.sqrt(s);
+          m[i] = s * a;
+          m[i + 1] = s * b;
+        }
+      }
+    }
+    i = -1;
+    while (++i <= j) {
+      s = (points[Math.min(j, i + 1)][0] - points[Math.max(0, i - 1)][0]) / (6 * (1 + m[i] * m[i]));
+      tangents.push([ s || 0, m[i] * s || 0 ]);
+    }
+    return tangents;
+  }
+  function d3_svg_lineMonotone(points) {
+    return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineMonotoneTangents(points));
+  }
+  d3.svg.line.radial = function() {
+    var line = d3_svg_line(d3_svg_lineRadial);
+    line.radius = line.x, delete line.x;
+    line.angle = line.y, delete line.y;
+    return line;
+  };
+  function d3_svg_lineRadial(points) {
+    var point, i = -1, n = points.length, r, a;
+    while (++i < n) {
+      point = points[i];
+      r = point[0];
+      a = point[1] + d3_svg_arcOffset;
+      point[0] = r * Math.cos(a);
+      point[1] = r * Math.sin(a);
+    }
+    return points;
+  }
+  function d3_svg_area(projection) {
+    var x0 = d3_geom_pointX, x1 = d3_geom_pointX, y0 = 0, y1 = d3_geom_pointY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, interpolateReverse = interpolate, L = "L", tension = .7;
+    function area(data) {
+      var segments = [], points0 = [], points1 = [], i = -1, n = data.length, d, fx0 = d3_functor(x0), fy0 = d3_functor(y0), fx1 = x0 === x1 ? function() {
+        return x;
+      } : d3_functor(x1), fy1 = y0 === y1 ? function() {
+        return y;
+      } : d3_functor(y1), x, y;
+      function segment() {
+        segments.push("M", interpolate(projection(points1), tension), L, interpolateReverse(projection(points0.reverse()), tension), "Z");
+      }
+      while (++i < n) {
+        if (defined.call(this, d = data[i], i)) {
+          points0.push([ x = +fx0.call(this, d, i), y = +fy0.call(this, d, i) ]);
+          points1.push([ +fx1.call(this, d, i), +fy1.call(this, d, i) ]);
+        } else if (points0.length) {
+          segment();
+          points0 = [];
+          points1 = [];
+        }
+      }
+      if (points0.length) segment();
+      return segments.length ? segments.join("") : null;
+    }
+    area.x = function(_) {
+      if (!arguments.length) return x1;
+      x0 = x1 = _;
+      return area;
+    };
+    area.x0 = function(_) {
+      if (!arguments.length) return x0;
+      x0 = _;
+      return area;
+    };
+    area.x1 = function(_) {
+      if (!arguments.length) return x1;
+      x1 = _;
+      return area;
+    };
+    area.y = function(_) {
+      if (!arguments.length) return y1;
+      y0 = y1 = _;
+      return area;
+    };
+    area.y0 = function(_) {
+      if (!arguments.length) return y0;
+      y0 = _;
+      return area;
+    };
+    area.y1 = function(_) {
+      if (!arguments.length) return y1;
+      y1 = _;
+      return area;
+    };
+    area.defined = function(_) {
+      if (!arguments.length) return defined;
+      defined = _;
+      return area;
+    };
+    area.interpolate = function(_) {
+      if (!arguments.length) return interpolateKey;
+      if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key;
+      interpolateReverse = interpolate.reverse || interpolate;
+      L = interpolate.closed ? "M" : "L";
+      return area;
+    };
+    area.tension = function(_) {
+      if (!arguments.length) return tension;
+      tension = _;
+      return area;
+    };
+    return area;
+  }
+  d3_svg_lineStepBefore.reverse = d3_svg_lineStepAfter;
+  d3_svg_lineStepAfter.reverse = d3_svg_lineStepBefore;
+  d3.svg.area = function() {
+    return d3_svg_area(d3_identity);
+  };
+  d3.svg.area.radial = function() {
+    var area = d3_svg_area(d3_svg_lineRadial);
+    area.radius = area.x, delete area.x;
+    area.innerRadius = area.x0, delete area.x0;
+    area.outerRadius = area.x1, delete area.x1;
+    area.angle = area.y, delete area.y;
+    area.startAngle = area.y0, delete area.y0;
+    area.endAngle = area.y1, delete area.y1;
+    return area;
+  };
+  d3.svg.chord = function() {
+    var source = d3_source, target = d3_target, radius = d3_svg_chordRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle;
+    function chord(d, i) {
+      var s = subgroup(this, source, d, i), t = subgroup(this, target, d, i);
+      return "M" + s.p0 + arc(s.r, s.p1, s.a1 - s.a0) + (equals(s, t) ? curve(s.r, s.p1, s.r, s.p0) : curve(s.r, s.p1, t.r, t.p0) + arc(t.r, t.p1, t.a1 - t.a0) + curve(t.r, t.p1, s.r, s.p0)) + "Z";
+    }
+    function subgroup(self, f, d, i) {
+      var subgroup = f.call(self, d, i), r = radius.call(self, subgroup, i), a0 = startAngle.call(self, subgroup, i) + d3_svg_arcOffset, a1 = endAngle.call(self, subgroup, i) + d3_svg_arcOffset;
+      return {
+        r: r,
+        a0: a0,
+        a1: a1,
+        p0: [ r * Math.cos(a0), r * Math.sin(a0) ],
+        p1: [ r * Math.cos(a1), r * Math.sin(a1) ]
+      };
+    }
+    function equals(a, b) {
+      return a.a0 == b.a0 && a.a1 == b.a1;
+    }
+    function arc(r, p, a) {
+      return "A" + r + "," + r + " 0 " + +(a > π) + ",1 " + p;
+    }
+    function curve(r0, p0, r1, p1) {
+      return "Q 0,0 " + p1;
+    }
+    chord.radius = function(v) {
+      if (!arguments.length) return radius;
+      radius = d3_functor(v);
+      return chord;
+    };
+    chord.source = function(v) {
+      if (!arguments.length) return source;
+      source = d3_functor(v);
+      return chord;
+    };
+    chord.target = function(v) {
+      if (!arguments.length) return target;
+      target = d3_functor(v);
+      return chord;
+    };
+    chord.startAngle = function(v) {
+      if (!arguments.length) return startAngle;
+      startAngle = d3_functor(v);
+      return chord;
+    };
+    chord.endAngle = function(v) {
+      if (!arguments.length) return endAngle;
+      endAngle = d3_functor(v);
+      return chord;
+    };
+    return chord;
+  };
+  function d3_svg_chordRadius(d) {
+    return d.radius;
+  }
+  d3.svg.diagonal = function() {
+    var source = d3_source, target = d3_target, projection = d3_svg_diagonalProjection;
+    function diagonal(d, i) {
+      var p0 = source.call(this, d, i), p3 = target.call(this, d, i), m = (p0.y + p3.y) / 2, p = [ p0, {
+        x: p0.x,
+        y: m
+      }, {
+        x: p3.x,
+        y: m
+      }, p3 ];
+      p = p.map(projection);
+      return "M" + p[0] + "C" + p[1] + " " + p[2] + " " + p[3];
+    }
+    diagonal.source = function(x) {
+      if (!arguments.length) return source;
+      source = d3_functor(x);
+      return diagonal;
+    };
+    diagonal.target = function(x) {
+      if (!arguments.length) return target;
+      target = d3_functor(x);
+      return diagonal;
+    };
+    diagonal.projection = function(x) {
+      if (!arguments.length) return projection;
+      projection = x;
+      return diagonal;
+    };
+    return diagonal;
+  };
+  function d3_svg_diagonalProjection(d) {
+    return [ d.x, d.y ];
+  }
+  d3.svg.diagonal.radial = function() {
+    var diagonal = d3.svg.diagonal(), projection = d3_svg_diagonalProjection, projection_ = diagonal.projection;
+    diagonal.projection = function(x) {
+      return arguments.length ? projection_(d3_svg_diagonalRadialProjection(projection = x)) : projection;
+    };
+    return diagonal;
+  };
+  function d3_svg_diagonalRadialProjection(projection) {
+    return function() {
+      var d = projection.apply(this, arguments), r = d[0], a = d[1] + d3_svg_arcOffset;
+      return [ r * Math.cos(a), r * Math.sin(a) ];
+    };
+  }
+  d3.svg.symbol = function() {
+    var type = d3_svg_symbolType, size = d3_svg_symbolSize;
+    function symbol(d, i) {
+      return (d3_svg_symbols.get(type.call(this, d, i)) || d3_svg_symbolCircle)(size.call(this, d, i));
+    }
+    symbol.type = function(x) {
+      if (!arguments.length) return type;
+      type = d3_functor(x);
+      return symbol;
+    };
+    symbol.size = function(x) {
+      if (!arguments.length) return size;
+      size = d3_functor(x);
+      return symbol;
+    };
+    return symbol;
+  };
+  function d3_svg_symbolSize() {
+    return 64;
+  }
+  function d3_svg_symbolType() {
+    return "circle";
+  }
+  function d3_svg_symbolCircle(size) {
+    var r = Math.sqrt(size / π);
+    return "M0," + r + "A" + r + "," + r + " 0 1,1 0," + -r + "A" + r + "," + r + " 0 1,1 0," + r + "Z";
+  }
+  var d3_svg_symbols = d3.map({
+    circle: d3_svg_symbolCircle,
+    cross: function(size) {
+      var r = Math.sqrt(size / 5) / 2;
+      return "M" + -3 * r + "," + -r + "H" + -r + "V" + -3 * r + "H" + r + "V" + -r + "H" + 3 * r + "V" + r + "H" + r + "V" + 3 * r + "H" + -r + "V" + r + "H" + -3 * r + "Z";
+    },
+    diamond: function(size) {
+      var ry = Math.sqrt(size / (2 * d3_svg_symbolTan30)), rx = ry * d3_svg_symbolTan30;
+      return "M0," + -ry + "L" + rx + ",0" + " 0," + ry + " " + -rx + ",0" + "Z";
+    },
+    square: function(size) {
+      var r = Math.sqrt(size) / 2;
+      return "M" + -r + "," + -r + "L" + r + "," + -r + " " + r + "," + r + " " + -r + "," + r + "Z";
+    },
+    "triangle-down": function(size) {
+      var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2;
+      return "M0," + ry + "L" + rx + "," + -ry + " " + -rx + "," + -ry + "Z";
+    },
+    "triangle-up": function(size) {
+      var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2;
+      return "M0," + -ry + "L" + rx + "," + ry + " " + -rx + "," + ry + "Z";
+    }
+  });
+  d3.svg.symbolTypes = d3_svg_symbols.keys();
+  var d3_svg_symbolSqrt3 = Math.sqrt(3), d3_svg_symbolTan30 = Math.tan(30 * d3_radians);
+  function d3_transition(groups, id) {
+    d3_subclass(groups, d3_transitionPrototype);
+    groups.id = id;
+    return groups;
+  }
+  var d3_transitionPrototype = [], d3_transitionId = 0, d3_transitionInheritId, d3_transitionInherit;
+  d3_transitionPrototype.call = d3_selectionPrototype.call;
+  d3_transitionPrototype.empty = d3_selectionPrototype.empty;
+  d3_transitionPrototype.node = d3_selectionPrototype.node;
+  d3_transitionPrototype.size = d3_selectionPrototype.size;
+  d3.transition = function(selection) {
+    return arguments.length ? d3_transitionInheritId ? selection.transition() : selection : d3_selectionRoot.transition();
+  };
+  d3.transition.prototype = d3_transitionPrototype;
+  d3_transitionPrototype.select = function(selector) {
+    var id = this.id, subgroups = [], subgroup, subnode, node;
+    selector = d3_selection_selector(selector);
+    for (var j = -1, m = this.length; ++j < m; ) {
+      subgroups.push(subgroup = []);
+      for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
+        if ((node = group[i]) && (subnode = selector.call(node, node.__data__, i, j))) {
+          if ("__data__" in node) subnode.__data__ = node.__data__;
+          d3_transitionNode(subnode, i, id, node.__transition__[id]);
+          subgroup.push(subnode);
+        } else {
+          subgroup.push(null);
+        }
+      }
+    }
+    return d3_transition(subgroups, id);
+  };
+  d3_transitionPrototype.selectAll = function(selector) {
+    var id = this.id, subgroups = [], subgroup, subnodes, node, subnode, transition;
+    selector = d3_selection_selectorAll(selector);
+    for (var j = -1, m = this.length; ++j < m; ) {
+      for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
+        if (node = group[i]) {
+          transition = node.__transition__[id];
+          subnodes = selector.call(node, node.__data__, i, j);
+          subgroups.push(subgroup = []);
+          for (var k = -1, o = subnodes.length; ++k < o; ) {
+            if (subnode = subnodes[k]) d3_transitionNode(subnode, k, id, transition);
+            subgroup.push(subnode);
+          }
+        }
+      }
+    }
+    return d3_transition(subgroups, id);
+  };
+  d3_transitionPrototype.filter = function(filter) {
+    var subgroups = [], subgroup, group, node;
+    if (typeof filter !== "function") filter = d3_selection_filter(filter);
+    for (var j = 0, m = this.length; j < m; j++) {
+      subgroups.push(subgroup = []);
+      for (var group = this[j], i = 0, n = group.length; i < n; i++) {
+        if ((node = group[i]) && filter.call(node, node.__data__, i, j)) {
+          subgroup.push(node);
+        }
+      }
+    }
+    return d3_transition(subgroups, this.id);
+  };
+  d3_transitionPrototype.tween = function(name, tween) {
+    var id = this.id;
+    if (arguments.length < 2) return this.node().__transition__[id].tween.get(name);
+    return d3_selection_each(this, tween == null ? function(node) {
+      node.__transition__[id].tween.remove(name);
+    } : function(node) {
+      node.__transition__[id].tween.set(name, tween);
+    });
+  };
+  function d3_transition_tween(groups, name, value, tween) {
+    var id = groups.id;
+    return d3_selection_each(groups, typeof value === "function" ? function(node, i, j) {
+      node.__transition__[id].tween.set(name, tween(value.call(node, node.__data__, i, j)));
+    } : (value = tween(value), function(node) {
+      node.__transition__[id].tween.set(name, value);
+    }));
+  }
+  d3_transitionPrototype.attr = function(nameNS, value) {
+    if (arguments.length < 2) {
+      for (value in nameNS) this.attr(value, nameNS[value]);
+      return this;
+    }
+    var interpolate = nameNS == "transform" ? d3_interpolateTransform : d3_interpolate, name = d3.ns.qualify(nameNS);
+    function attrNull() {
+      this.removeAttribute(name);
+    }
+    function attrNullNS() {
+      this.removeAttributeNS(name.space, name.local);
+    }
+    function attrTween(b) {
+      return b == null ? attrNull : (b += "", function() {
+        var a = this.getAttribute(name), i;
+        return a !== b && (i = interpolate(a, b), function(t) {
+          this.setAttribute(name, i(t));
+        });
+      });
+    }
+    function attrTweenNS(b) {
+      return b == null ? attrNullNS : (b += "", function() {
+        var a = this.getAttributeNS(name.space, name.local), i;
+        return a !== b && (i = interpolate(a, b), function(t) {
+          this.setAttributeNS(name.space, name.local, i(t));
+        });
+      });
+    }
+    return d3_transition_tween(this, "attr." + nameNS, value, name.local ? attrTweenNS : attrTween);
+  };
+  d3_transitionPrototype.attrTween = function(nameNS, tween) {
+    var name = d3.ns.qualify(nameNS);
+    function attrTween(d, i) {
+      var f = tween.call(this, d, i, this.getAttribute(name));
+      return f && function(t) {
+        this.setAttribute(name, f(t));
+      };
+    }
+    function attrTweenNS(d, i) {
+      var f = tween.call(this, d, i, this.getAttributeNS(name.space, name.local));
+      return f && function(t) {
+        this.setAttributeNS(name.space, name.local, f(t));
+      };
+    }
+    return this.tween("attr." + nameNS, name.local ? attrTweenNS : attrTween);
+  };
+  d3_transitionPrototype.style = function(name, value, priority) {
+    var n = arguments.length;
+    if (n < 3) {
+      if (typeof name !== "string") {
+        if (n < 2) value = "";
+        for (priority in name) this.style(priority, name[priority], value);
+        return this;
+      }
+      priority = "";
+    }
+    function styleNull() {
+      this.style.removeProperty(name);
+    }
+    function styleString(b) {
+      return b == null ? styleNull : (b += "", function() {
+        var a = d3_window.getComputedStyle(this, null).getPropertyValue(name), i;
+        return a !== b && (i = d3_interpolate(a, b), function(t) {
+          this.style.setProperty(name, i(t), priority);
+        });
+      });
+    }
+    return d3_transition_tween(this, "style." + name, value, styleString);
+  };
+  d3_transitionPrototype.styleTween = function(name, tween, priority) {
+    if (arguments.length < 3) priority = "";
+    function styleTween(d, i) {
+      var f = tween.call(this, d, i, d3_window.getComputedStyle(this, null).getPropertyValue(name));
+      return f && function(t) {
+        this.style.setProperty(name, f(t), priority);
+      };
+    }
+    return this.tween("style." + name, styleTween);
+  };
+  d3_transitionPrototype.text = function(value) {
+    return d3_transition_tween(this, "text", value, d3_transition_text);
+  };
+  function d3_transition_text(b) {
+    if (b == null) b = "";
+    return function() {
+      this.textContent = b;
+    };
+  }
+  d3_transitionPrototype.remove = function() {
+    return this.each("end.transition", function() {
+      var p;
+      if (this.__transition__.count < 2 && (p = this.parentNode)) p.removeChild(this);
+    });
+  };
+  d3_transitionPrototype.ease = function(value) {
+    var id = this.id;
+    if (arguments.length < 1) return this.node().__transition__[id].ease;
+    if (typeof value !== "function") value = d3.ease.apply(d3, arguments);
+    return d3_selection_each(this, function(node) {
+      node.__transition__[id].ease = value;
+    });
+  };
+  d3_transitionPrototype.delay = function(value) {
+    var id = this.id;
+    if (arguments.length < 1) return this.node().__transition__[id].delay;
+    return d3_selection_each(this, typeof value === "function" ? function(node, i, j) {
+      node.__transition__[id].delay = +value.call(node, node.__data__, i, j);
+    } : (value = +value, function(node) {
+      node.__transition__[id].delay = value;
+    }));
+  };
+  d3_transitionPrototype.duration = function(value) {
+    var id = this.id;
+    if (arguments.length < 1) return this.node().__transition__[id].duration;
+    return d3_selection_each(this, typeof value === "function" ? function(node, i, j) {
+      node.__transition__[id].duration = Math.max(1, value.call(node, node.__data__, i, j));
+    } : (value = Math.max(1, value), function(node) {
+      node.__transition__[id].duration = value;
+    }));
+  };
+  d3_transitionPrototype.each = function(type, listener) {
+    var id = this.id;
+    if (arguments.length < 2) {
+      var inherit = d3_transitionInherit, inheritId = d3_transitionInheritId;
+      d3_transitionInheritId = id;
+      d3_selection_each(this, function(node, i, j) {
+        d3_transitionInherit = node.__transition__[id];
+        type.call(node, node.__data__, i, j);
+      });
+      d3_transitionInherit = inherit;
+      d3_transitionInheritId = inheritId;
+    } else {
+      d3_selection_each(this, function(node) {
+        var transition = node.__transition__[id];
+        (transition.event || (transition.event = d3.dispatch("start", "end"))).on(type, listener);
+      });
+    }
+    return this;
+  };
+  d3_transitionPrototype.transition = function() {
+    var id0 = this.id, id1 = ++d3_transitionId, subgroups = [], subgroup, group, node, transition;
+    for (var j = 0, m = this.length; j < m; j++) {
+      subgroups.push(subgroup = []);
+      for (var group = this[j], i = 0, n = group.length; i < n; i++) {
+        if (node = group[i]) {
+          transition = Object.create(node.__transition__[id0]);
+          transition.delay += transition.duration;
+          d3_transitionNode(node, i, id1, transition);
+        }
+        subgroup.push(node);
+      }
+    }
+    return d3_transition(subgroups, id1);
+  };
+  function d3_transitionNode(node, i, id, inherit) {
+    var lock = node.__transition__ || (node.__transition__ = {
+      active: 0,
+      count: 0
+    }), transition = lock[id];
+    if (!transition) {
+      var time = inherit.time;
+      transition = lock[id] = {
+        tween: new d3_Map(),
+        time: time,
+        ease: inherit.ease,
+        delay: inherit.delay,
+        duration: inherit.duration
+      };
+      ++lock.count;
+      d3.timer(function(elapsed) {
+        var d = node.__data__, ease = transition.ease, delay = transition.delay, duration = transition.duration, timer = d3_timer_active, tweened = [];
+        timer.t = delay + time;
+        if (delay <= elapsed) return start(elapsed - delay);
+        timer.c = start;
+        function start(elapsed) {
+          if (lock.active > id) return stop();
+          lock.active = id;
+          transition.event && transition.event.start.call(node, d, i);
+          transition.tween.forEach(function(key, value) {
+            if (value = value.call(node, d, i)) {
+              tweened.push(value);
+            }
+          });
+          d3.timer(function() {
+            timer.c = tick(elapsed || 1) ? d3_true : tick;
+            return 1;
+          }, 0, time);
+        }
+        function tick(elapsed) {
+          if (lock.active !== id) return stop();
+          var t = elapsed / duration, e = ease(t), n = tweened.length;
+          while (n > 0) {
+            tweened[--n].call(node, e);
+          }
+          if (t >= 1) {
+            transition.event && transition.event.end.call(node, d, i);
+            return stop();
+          }
+        }
+        function stop() {
+          if (--lock.count) delete lock[id]; else delete node.__transition__;
+          return 1;
+        }
+      }, 0, time);
+    }
+  }
+  d3.svg.axis = function() {
+    var scale = d3.scale.linear(), orient = d3_svg_axisDefaultOrient, innerTickSize = 6, outerTickSize = 6, tickPadding = 3, tickArguments_ = [ 10 ], tickValues = null, tickFormat_;
+    function axis(g) {
+      g.each(function() {
+        var g = d3.select(this);
+        var scale0 = this.__chart__ || scale, scale1 = this.__chart__ = scale.copy();
+        var ticks = tickValues == null ? scale1.ticks ? scale1.ticks.apply(scale1, tickArguments_) : scale1.domain() : tickValues, tickFormat = tickFormat_ == null ? scale1.tickFormat ? scale1.tickFormat.apply(scale1, tickArguments_) : d3_identity : tickFormat_, tick = g.selectAll(".tick").data(ticks, scale1), tickEnter = tick.enter().insert("g", ".domain").attr("class", "tick").style("opacity", ε), tickExit = d3.transition(tick.exit()).style("opacity", ε).remove(), tickUpdate = d3.transition(tick.order()).style("opacity", 1), tickTransform;
+        var range = d3_scaleRange(scale1), path = g.selectAll(".domain").data([ 0 ]), pathUpdate = (path.enter().append("path").attr("class", "domain"), 
+        d3.transition(path));
+        tickEnter.append("line");
+        tickEnter.append("text");
+        var lineEnter = tickEnter.select("line"), lineUpdate = tickUpdate.select("line"), text = tick.select("text").text(tickFormat), textEnter = tickEnter.select("text"), textUpdate = tickUpdate.select("text");
+        switch (orient) {
+         case "bottom":
+          {
+            tickTransform = d3_svg_axisX;
+            lineEnter.attr("y2", innerTickSize);
+            textEnter.attr("y", Math.max(innerTickSize, 0) + tickPadding);
+            lineUpdate.attr("x2", 0).attr("y2", innerTickSize);
+            textUpdate.attr("x", 0).attr("y", Math.max(innerTickSize, 0) + tickPadding);
+            text.attr("dy", ".71em").style("text-anchor", "middle");
+            pathUpdate.attr("d", "M" + range[0] + "," + outerTickSize + "V0H" + range[1] + "V" + outerTickSize);
+            break;
+          }
+
+         case "top":
+          {
+            tickTransform = d3_svg_axisX;
+            lineEnter.attr("y2", -innerTickSize);
+            textEnter.attr("y", -(Math.max(innerTickSize, 0) + tickPadding));
+            lineUpdate.attr("x2", 0).attr("y2", -innerTickSize);
+            textUpdate.attr("x", 0).attr("y", -(Math.max(innerTickSize, 0) + tickPadding));
+            text.attr("dy", "0em").style("text-anchor", "middle");
+            pathUpdate.attr("d", "M" + range[0] + "," + -outerTickSize + "V0H" + range[1] + "V" + -outerTickSize);
+            break;
+          }
+
+         case "left":
+          {
+            tickTransform = d3_svg_axisY;
+            lineEnter.attr("x2", -innerTickSize);
+            textEnter.attr("x", -(Math.max(innerTickSize, 0) + tickPadding));
+            lineUpdate.attr("x2", -innerTickSize).attr("y2", 0);
+            textUpdate.attr("x", -(Math.max(innerTickSize, 0) + tickPadding)).attr("y", 0);
+            text.attr("dy", ".32em").style("text-anchor", "end");
+            pathUpdate.attr("d", "M" + -outerTickSize + "," + range[0] + "H0V" + range[1] + "H" + -outerTickSize);
+            break;
+          }
+
+         case "right":
+          {
+            tickTransform = d3_svg_axisY;
+            lineEnter.attr("x2", innerTickSize);
+            textEnter.attr("x", Math.max(innerTickSize, 0) + tickPadding);
+            lineUpdate.attr("x2", innerTickSize).attr("y2", 0);
+            textUpdate.attr("x", Math.max(innerTickSize, 0) + tickPadding).attr("y", 0);
+            text.attr("dy", ".32em").style("text-anchor", "start");
+            pathUpdate.attr("d", "M" + outerTickSize + "," + range[0] + "H0V" + range[1] + "H" + outerTickSize);
+            break;
+          }
+        }
+        if (scale1.rangeBand) {
+          var x = scale1, dx = x.rangeBand() / 2;
+          scale0 = scale1 = function(d) {
+            return x(d) + dx;
+          };
+        } else if (scale0.rangeBand) {
+          scale0 = scale1;
+        } else {
+          tickExit.call(tickTransform, scale1);
+        }
+        tickEnter.call(tickTransform, scale0);
+        tickUpdate.call(tickTransform, scale1);
+      });
+    }
+    axis.scale = function(x) {
+      if (!arguments.length) return scale;
+      scale = x;
+      return axis;
+    };
+    axis.orient = function(x) {
+      if (!arguments.length) return orient;
+      orient = x in d3_svg_axisOrients ? x + "" : d3_svg_axisDefaultOrient;
+      return axis;
+    };
+    axis.ticks = function() {
+      if (!arguments.length) return tickArguments_;
+      tickArguments_ = arguments;
+      return axis;
+    };
+    axis.tickValues = function(x) {
+      if (!arguments.length) return tickValues;
+      tickValues = x;
+      return axis;
+    };
+    axis.tickFormat = function(x) {
+      if (!arguments.length) return tickFormat_;
+      tickFormat_ = x;
+      return axis;
+    };
+    axis.tickSize = function(x) {
+      var n = arguments.length;
+      if (!n) return innerTickSize;
+      innerTickSize = +x;
+      outerTickSize = +arguments[n - 1];
+      return axis;
+    };
+    axis.innerTickSize = function(x) {
+      if (!arguments.length) return innerTickSize;
+      innerTickSize = +x;
+      return axis;
+    };
+    axis.outerTickSize = function(x) {
+      if (!arguments.length) return outerTickSize;
+      outerTickSize = +x;
+      return axis;
+    };
+    axis.tickPadding = function(x) {
+      if (!arguments.length) return tickPadding;
+      tickPadding = +x;
+      return axis;
+    };
+    axis.tickSubdivide = function() {
+      return arguments.length && axis;
+    };
+    return axis;
+  };
+  var d3_svg_axisDefaultOrient = "bottom", d3_svg_axisOrients = {
+    top: 1,
+    right: 1,
+    bottom: 1,
+    left: 1
+  };
+  function d3_svg_axisX(selection, x) {
+    selection.attr("transform", function(d) {
+      return "translate(" + x(d) + ",0)";
+    });
+  }
+  function d3_svg_axisY(selection, y) {
+    selection.attr("transform", function(d) {
+      return "translate(0," + y(d) + ")";
+    });
+  }
+  d3.svg.brush = function() {
+    var event = d3_eventDispatch(brush, "brushstart", "brush", "brushend"), x = null, y = null, xExtent = [ 0, 0 ], yExtent = [ 0, 0 ], xExtentDomain, yExtentDomain, xClamp = true, yClamp = true, resizes = d3_svg_brushResizes[0];
+    function brush(g) {
+      g.each(function() {
+        var g = d3.select(this).style("pointer-events", "all").style("-webkit-tap-highlight-color", "rgba(0,0,0,0)").on("mousedown.brush", brushstart).on("touchstart.brush", brushstart);
+        var background = g.selectAll(".background").data([ 0 ]);
+        background.enter().append("rect").attr("class", "background").style("visibility", "hidden").style("cursor", "crosshair");
+        g.selectAll(".extent").data([ 0 ]).enter().append("rect").attr("class", "extent").style("cursor", "move");
+        var resize = g.selectAll(".resize").data(resizes, d3_identity);
+        resize.exit().remove();
+        resize.enter().append("g").attr("class", function(d) {
+          return "resize " + d;
+        }).style("cursor", function(d) {
+          return d3_svg_brushCursor[d];
+        }).append("rect").attr("x", function(d) {
+          return /[ew]$/.test(d) ? -3 : null;
+        }).attr("y", function(d) {
+          return /^[ns]/.test(d) ? -3 : null;
+        }).attr("width", 6).attr("height", 6).style("visibility", "hidden");
+        resize.style("display", brush.empty() ? "none" : null);
+        var gUpdate = d3.transition(g), backgroundUpdate = d3.transition(background), range;
+        if (x) {
+          range = d3_scaleRange(x);
+          backgroundUpdate.attr("x", range[0]).attr("width", range[1] - range[0]);
+          redrawX(gUpdate);
+        }
+        if (y) {
+          range = d3_scaleRange(y);
+          backgroundUpdate.attr("y", range[0]).attr("height", range[1] - range[0]);
+          redrawY(gUpdate);
+        }
+        redraw(gUpdate);
+      });
+    }
+    brush.event = function(g) {
+      g.each(function() {
+        var event_ = event.of(this, arguments), extent1 = {
+          x: xExtent,
+          y: yExtent,
+          i: xExtentDomain,
+          j: yExtentDomain
+        }, extent0 = this.__chart__ || extent1;
+        this.__chart__ = extent1;
+        if (d3_transitionInheritId) {
+          d3.select(this).transition().each("start.brush", function() {
+            xExtentDomain = extent0.i;
+            yExtentDomain = extent0.j;
+            xExtent = extent0.x;
+            yExtent = extent0.y;
+            event_({
+              type: "brushstart"
+            });
+          }).tween("brush:brush", function() {
+            var xi = d3_interpolateArray(xExtent, extent1.x), yi = d3_interpolateArray(yExtent, extent1.y);
+            xExtentDomain = yExtentDomain = null;
+            return function(t) {
+              xExtent = extent1.x = xi(t);
+              yExtent = extent1.y = yi(t);
+              event_({
+                type: "brush",
+                mode: "resize"
+              });
+            };
+          }).each("end.brush", function() {
+            xExtentDomain = extent1.i;
+            yExtentDomain = extent1.j;
+            event_({
+              type: "brush",
+              mode: "resize"
+            });
+            event_({
+              type: "brushend"
+            });
+          });
+        } else {
+          event_({
+            type: "brushstart"
+          });
+          event_({
+            type: "brush",
+            mode: "resize"
+          });
+          event_({
+            type: "brushend"
+          });
+        }
+      });
+    };
+    function redraw(g) {
+      g.selectAll(".resize").attr("transform", function(d) {
+        return "translate(" + xExtent[+/e$/.test(d)] + "," + yExtent[+/^s/.test(d)] + ")";
+      });
+    }
+    function redrawX(g) {
+      g.select(".extent").attr("x", xExtent[0]);
+      g.selectAll(".extent,.n>rect,.s>rect").attr("width", xExtent[1] - xExtent[0]);
+    }
+    function redrawY(g) {
+      g.select(".extent").attr("y", yExtent[0]);
+      g.selectAll(".extent,.e>rect,.w>rect").attr("height", yExtent[1] - yExtent[0]);
+    }
+    function brushstart() {
+      var target = this, eventTarget = d3.select(d3.event.target), event_ = event.of(target, arguments), g = d3.select(target), resizing = eventTarget.datum(), resizingX = !/^(n|s)$/.test(resizing) && x, resizingY = !/^(e|w)$/.test(resizing) && y, dragging = eventTarget.classed("extent"), dragRestore = d3_event_dragSuppress(), center, origin = d3.mouse(target), offset;
+      var w = d3.select(d3_window).on("keydown.brush", keydown).on("keyup.brush", keyup);
+      if (d3.event.changedTouches) {
+        w.on("touchmove.brush", brushmove).on("touchend.brush", brushend);
+      } else {
+        w.on("mousemove.brush", brushmove).on("mouseup.brush", brushend);
+      }
+      g.interrupt().selectAll("*").interrupt();
+      if (dragging) {
+        origin[0] = xExtent[0] - origin[0];
+        origin[1] = yExtent[0] - origin[1];
+      } else if (resizing) {
+        var ex = +/w$/.test(resizing), ey = +/^n/.test(resizing);
+        offset = [ xExtent[1 - ex] - origin[0], yExtent[1 - ey] - origin[1] ];
+        origin[0] = xExtent[ex];
+        origin[1] = yExtent[ey];
+      } else if (d3.event.altKey) center = origin.slice();
+      g.style("pointer-events", "none").selectAll(".resize").style("display", null);
+      d3.select("body").style("cursor", eventTarget.style("cursor"));
+      event_({
+        type: "brushstart"
+      });
+      brushmove();
+      function keydown() {
+        if (d3.event.keyCode == 32) {
+          if (!dragging) {
+            center = null;
+            origin[0] -= xExtent[1];
+            origin[1] -= yExtent[1];
+            dragging = 2;
+          }
+          d3_eventPreventDefault();
+        }
+      }
+      function keyup() {
+        if (d3.event.keyCode == 32 && dragging == 2) {
+          origin[0] += xExtent[1];
+          origin[1] += yExtent[1];
+          dragging = 0;
+          d3_eventPreventDefault();
+        }
+      }
+      function brushmove() {
+        var point = d3.mouse(target), moved = false;
+        if (offset) {
+          point[0] += offset[0];
+          point[1] += offset[1];
+        }
+        if (!dragging) {
+          if (d3.event.altKey) {
+            if (!center) center = [ (xExtent[0] + xExtent[1]) / 2, (yExtent[0] + yExtent[1]) / 2 ];
+            origin[0] = xExtent[+(point[0] < center[0])];
+            origin[1] = yExtent[+(point[1] < center[1])];
+          } else center = null;
+        }
+        if (resizingX && move1(point, x, 0)) {
+          redrawX(g);
+          moved = true;
+        }
+        if (resizingY && move1(point, y, 1)) {
+          redrawY(g);
+          moved = true;
+        }
+        if (moved) {
+          redraw(g);
+          event_({
+            type: "brush",
+            mode: dragging ? "move" : "resize"
+          });
+        }
+      }
+      function move1(point, scale, i) {
+        var range = d3_scaleRange(scale), r0 = range[0], r1 = range[1], position = origin[i], extent = i ? yExtent : xExtent, size = extent[1] - extent[0], min, max;
+        if (dragging) {
+          r0 -= position;
+          r1 -= size + position;
+        }
+        min = (i ? yClamp : xClamp) ? Math.max(r0, Math.min(r1, point[i])) : point[i];
+        if (dragging) {
+          max = (min += position) + size;
+        } else {
+          if (center) position = Math.max(r0, Math.min(r1, 2 * center[i] - min));
+          if (position < min) {
+            max = min;
+            min = position;
+          } else {
+            max = position;
+          }
+        }
+        if (extent[0] != min || extent[1] != max) {
+          if (i) yExtentDomain = null; else xExtentDomain = null;
+          extent[0] = min;
+          extent[1] = max;
+          return true;
+        }
+      }
+      function brushend() {
+        brushmove();
+        g.style("pointer-events", "all").selectAll(".resize").style("display", brush.empty() ? "none" : null);
+        d3.select("body").style("cursor", null);
+        w.on("mousemove.brush", null).on("mouseup.brush", null).on("touchmove.brush", null).on("touchend.brush", null).on("keydown.brush", null).on("keyup.brush", null);
+        dragRestore();
+        event_({
+          type: "brushend"
+        });
+      }
+    }
+    brush.x = function(z) {
+      if (!arguments.length) return x;
+      x = z;
+      resizes = d3_svg_brushResizes[!x << 1 | !y];
+      return brush;
+    };
+    brush.y = function(z) {
+      if (!arguments.length) return y;
+      y = z;
+      resizes = d3_svg_brushResizes[!x << 1 | !y];
+      return brush;
+    };
+    brush.clamp = function(z) {
+      if (!arguments.length) return x && y ? [ xClamp, yClamp ] : x ? xClamp : y ? yClamp : null;
+      if (x && y) xClamp = !!z[0], yClamp = !!z[1]; else if (x) xClamp = !!z; else if (y) yClamp = !!z;
+      return brush;
+    };
+    brush.extent = function(z) {
+      var x0, x1, y0, y1, t;
+      if (!arguments.length) {
+        if (x) {
+          if (xExtentDomain) {
+            x0 = xExtentDomain[0], x1 = xExtentDomain[1];
+          } else {
+            x0 = xExtent[0], x1 = xExtent[1];
+            if (x.invert) x0 = x.invert(x0), x1 = x.invert(x1);
+            if (x1 < x0) t = x0, x0 = x1, x1 = t;
+          }
+        }
+        if (y) {
+          if (yExtentDomain) {
+            y0 = yExtentDomain[0], y1 = yExtentDomain[1];
+          } else {
+            y0 = yExtent[0], y1 = yExtent[1];
+            if (y.invert) y0 = y.invert(y0), y1 = y.invert(y1);
+            if (y1 < y0) t = y0, y0 = y1, y1 = t;
+          }
+        }
+        return x && y ? [ [ x0, y0 ], [ x1, y1 ] ] : x ? [ x0, x1 ] : y && [ y0, y1 ];
+      }
+      if (x) {
+        x0 = z[0], x1 = z[1];
+        if (y) x0 = x0[0], x1 = x1[0];
+        xExtentDomain = [ x0, x1 ];
+        if (x.invert) x0 = x(x0), x1 = x(x1);
+        if (x1 < x0) t = x0, x0 = x1, x1 = t;
+        if (x0 != xExtent[0] || x1 != xExtent[1]) xExtent = [ x0, x1 ];
+      }
+      if (y) {
+        y0 = z[0], y1 = z[1];
+        if (x) y0 = y0[1], y1 = y1[1];
+        yExtentDomain = [ y0, y1 ];
+        if (y.invert) y0 = y(y0), y1 = y(y1);
+        if (y1 < y0) t = y0, y0 = y1, y1 = t;
+        if (y0 != yExtent[0] || y1 != yExtent[1]) yExtent = [ y0, y1 ];
+      }
+      return brush;
+    };
+    brush.clear = function() {
+      if (!brush.empty()) {
+        xExtent = [ 0, 0 ], yExtent = [ 0, 0 ];
+        xExtentDomain = yExtentDomain = null;
+      }
+      return brush;
+    };
+    brush.empty = function() {
+      return !!x && xExtent[0] == xExtent[1] || !!y && yExtent[0] == yExtent[1];
+    };
+    return d3.rebind(brush, event, "on");
+  };
+  var d3_svg_brushCursor = {
+    n: "ns-resize",
+    e: "ew-resize",
+    s: "ns-resize",
+    w: "ew-resize",
+    nw: "nwse-resize",
+    ne: "nesw-resize",
+    se: "nwse-resize",
+    sw: "nesw-resize"
+  };
+  var d3_svg_brushResizes = [ [ "n", "e", "s", "w", "nw", "ne", "se", "sw" ], [ "e", "w" ], [ "n", "s" ], [] ];
+  var d3_time_format = d3_time.format = d3_locale_enUS.timeFormat;
+  var d3_time_formatUtc = d3_time_format.utc;
+  var d3_time_formatIso = d3_time_formatUtc("%Y-%m-%dT%H:%M:%S.%LZ");
+  d3_time_format.iso = Date.prototype.toISOString && +new Date("2000-01-01T00:00:00.000Z") ? d3_time_formatIsoNative : d3_time_formatIso;
+  function d3_time_formatIsoNative(date) {
+    return date.toISOString();
+  }
+  d3_time_formatIsoNative.parse = function(string) {
+    var date = new Date(string);
+    return isNaN(date) ? null : date;
+  };
+  d3_time_formatIsoNative.toString = d3_time_formatIso.toString;
+  d3_time.second = d3_time_interval(function(date) {
+    return new d3_date(Math.floor(date / 1e3) * 1e3);
+  }, function(date, offset) {
+    date.setTime(date.getTime() + Math.floor(offset) * 1e3);
+  }, function(date) {
+    return date.getSeconds();
+  });
+  d3_time.seconds = d3_time.second.range;
+  d3_time.seconds.utc = d3_time.second.utc.range;
+  d3_time.minute = d3_time_interval(function(date) {
+    return new d3_date(Math.floor(date / 6e4) * 6e4);
+  }, function(date, offset) {
+    date.setTime(date.getTime() + Math.floor(offset) * 6e4);
+  }, function(date) {
+    return date.getMinutes();
+  });
+  d3_time.minutes = d3_time.minute.range;
+  d3_time.minutes.utc = d3_time.minute.utc.range;
+  d3_time.hour = d3_time_interval(function(date) {
+    var timezone = date.getTimezoneOffset() / 60;
+    return new d3_date((Math.floor(date / 36e5 - timezone) + timezone) * 36e5);
+  }, function(date, offset) {
+    date.setTime(date.getTime() + Math.floor(offset) * 36e5);
+  }, function(date) {
+    return date.getHours();
+  });
+  d3_time.hours = d3_time.hour.range;
+  d3_time.hours.utc = d3_time.hour.utc.range;
+  d3_time.month = d3_time_interval(function(date) {
+    date = d3_time.day(date);
+    date.setDate(1);
+    return date;
+  }, function(date, offset) {
+    date.setMonth(date.getMonth() + offset);
+  }, function(date) {
+    return date.getMonth();
+  });
+  d3_time.months = d3_time.month.range;
+  d3_time.months.utc = d3_time.month.utc.range;
+  function d3_time_scale(linear, methods, format) {
+    function scale(x) {
+      return linear(x);
+    }
+    scale.invert = function(x) {
+      return d3_time_scaleDate(linear.invert(x));
+    };
+    scale.domain = function(x) {
+      if (!arguments.length) return linear.domain().map(d3_time_scaleDate);
+      linear.domain(x);
+      return scale;
+    };
+    function tickMethod(extent, count) {
+      var span = extent[1] - extent[0], target = span / count, i = d3.bisect(d3_time_scaleSteps, target);
+      return i == d3_time_scaleSteps.length ? [ methods.year, d3_scale_linearTickRange(extent.map(function(d) {
+        return d / 31536e6;
+      }), count)[2] ] : !i ? [ d3_time_scaleMilliseconds, d3_scale_linearTickRange(extent, count)[2] ] : methods[target / d3_time_scaleSteps[i - 1] < d3_time_scaleSteps[i] / target ? i - 1 : i];
+    }
+    scale.nice = function(interval, skip) {
+      var domain = scale.domain(), extent = d3_scaleExtent(domain), method = interval == null ? tickMethod(extent, 10) : typeof interval === "number" && tickMethod(extent, interval);
+      if (method) interval = method[0], skip = method[1];
+      function skipped(date) {
+        return !isNaN(date) && !interval.range(date, d3_time_scaleDate(+date + 1), skip).length;
+      }
+      return scale.domain(d3_scale_nice(domain, skip > 1 ? {
+        floor: function(date) {
+          while (skipped(date = interval.floor(date))) date = d3_time_scaleDate(date - 1);
+          return date;
+        },
+        ceil: function(date) {
+          while (skipped(date = interval.ceil(date))) date = d3_time_scaleDate(+date + 1);
+          return date;
+        }
+      } : interval));
+    };
+    scale.ticks = function(interval, skip) {
+      var extent = d3_scaleExtent(scale.domain()), method = interval == null ? tickMethod(extent, 10) : typeof interval === "number" ? tickMethod(extent, interval) : !interval.range && [ {
+        range: interval
+      }, skip ];
+      if (method) interval = method[0], skip = method[1];
+      return interval.range(extent[0], d3_time_scaleDate(+extent[1] + 1), skip < 1 ? 1 : skip);
+    };
+    scale.tickFormat = function() {
+      return format;
+    };
+    scale.copy = function() {
+      return d3_time_scale(linear.copy(), methods, format);
+    };
+    return d3_scale_linearRebind(scale, linear);
+  }
+  function d3_time_scaleDate(t) {
+    return new Date(t);
+  }
+  var d3_time_scaleSteps = [ 1e3, 5e3, 15e3, 3e4, 6e4, 3e5, 9e5, 18e5, 36e5, 108e5, 216e5, 432e5, 864e5, 1728e5, 6048e5, 2592e6, 7776e6, 31536e6 ];
+  var d3_time_scaleLocalMethods = [ [ d3_time.second, 1 ], [ d3_time.second, 5 ], [ d3_time.second, 15 ], [ d3_time.second, 30 ], [ d3_time.minute, 1 ], [ d3_time.minute, 5 ], [ d3_time.minute, 15 ], [ d3_time.minute, 30 ], [ d3_time.hour, 1 ], [ d3_time.hour, 3 ], [ d3_time.hour, 6 ], [ d3_time.hour, 12 ], [ d3_time.day, 1 ], [ d3_time.day, 2 ], [ d3_time.week, 1 ], [ d3_time.month, 1 ], [ d3_time.month, 3 ], [ d3_time.year, 1 ] ];
+  var d3_time_scaleLocalFormat = d3_time_format.multi([ [ ".%L", function(d) {
+    return d.getMilliseconds();
+  } ], [ ":%S", function(d) {
+    return d.getSeconds();
+  } ], [ "%I:%M", function(d) {
+    return d.getMinutes();
+  } ], [ "%I %p", function(d) {
+    return d.getHours();
+  } ], [ "%a %d", function(d) {
+    return d.getDay() && d.getDate() != 1;
+  } ], [ "%b %d", function(d) {
+    return d.getDate() != 1;
+  } ], [ "%B", function(d) {
+    return d.getMonth();
+  } ], [ "%Y", d3_true ] ]);
+  var d3_time_scaleMilliseconds = {
+    range: function(start, stop, step) {
+      return d3.range(Math.ceil(start / step) * step, +stop, step).map(d3_time_scaleDate);
+    },
+    floor: d3_identity,
+    ceil: d3_identity
+  };
+  d3_time_scaleLocalMethods.year = d3_time.year;
+  d3_time.scale = function() {
+    return d3_time_scale(d3.scale.linear(), d3_time_scaleLocalMethods, d3_time_scaleLocalFormat);
+  };
+  var d3_time_scaleUtcMethods = d3_time_scaleLocalMethods.map(function(m) {
+    return [ m[0].utc, m[1] ];
+  });
+  var d3_time_scaleUtcFormat = d3_time_formatUtc.multi([ [ ".%L", function(d) {
+    return d.getUTCMilliseconds();
+  } ], [ ":%S", function(d) {
+    return d.getUTCSeconds();
+  } ], [ "%I:%M", function(d) {
+    return d.getUTCMinutes();
+  } ], [ "%I %p", function(d) {
+    return d.getUTCHours();
+  } ], [ "%a %d", function(d) {
+    return d.getUTCDay() && d.getUTCDate() != 1;
+  } ], [ "%b %d", function(d) {
+    return d.getUTCDate() != 1;
+  } ], [ "%B", function(d) {
+    return d.getUTCMonth();
+  } ], [ "%Y", d3_true ] ]);
+  d3_time_scaleUtcMethods.year = d3_time.year.utc;
+  d3_time.scale.utc = function() {
+    return d3_time_scale(d3.scale.linear(), d3_time_scaleUtcMethods, d3_time_scaleUtcFormat);
+  };
+  d3.text = d3_xhrType(function(request) {
+    return request.responseText;
+  });
+  d3.json = function(url, callback) {
+    return d3_xhr(url, "application/json", d3_json, callback);
+  };
+  function d3_json(request) {
+    return JSON.parse(request.responseText);
+  }
+  d3.html = function(url, callback) {
+    throw "disallowed by chromium security";
+    return d3_xhr(url, "text/html", d3_html, callback);
+  };
+  function d3_html(request) {
+    throw "disallowed by chromium security";
+    var range = d3_document.createRange();
+    range.selectNode(d3_document.body);
+    return range.createContextualFragment(request.responseText);
+  }
+  d3.xml = d3_xhrType(function(request) {
+    return request.responseXML;
+  });
+  if (typeof define === "function" && define.amd) {
+    define(d3);
+  } else if (typeof module === "object" && module.exports) {
+    module.exports = d3;
+  } else {
+    this.d3 = d3;
+  }
+}();
\ No newline at end of file
diff --git a/runtime/tools/create_snapshot_bin.py b/runtime/tools/create_snapshot_bin.py
index 344c4e3..78213cf 100755
--- a/runtime/tools/create_snapshot_bin.py
+++ b/runtime/tools/create_snapshot_bin.py
@@ -104,7 +104,9 @@
     return 1
 
   # Setup arguments to the snapshot generator binary.
-  script_args = ["--error_on_bad_type", "--error_on_bad_override"]
+  script_args = ["--ignore_unrecognized_flags",
+                 "--error_on_bad_type",
+                 "--error_on_bad_override"]
 
   # Pass along the package_root if there is one.
   if options.package_root:
diff --git a/runtime/vm/BUILD.gn b/runtime/vm/BUILD.gn
index 2db9a6e..ea968d8 100644
--- a/runtime/vm/BUILD.gn
+++ b/runtime/vm/BUILD.gn
@@ -55,7 +55,23 @@
 
   set_sources_assignment_filter(["*_test.cc", "*_test.h"])
   sources = vm_sources_list.sources
-            - ["vtune.cc", "vtune.h"]
+  include_dirs = [
+    "..",
+  ]
+}
+
+
+static_library("libdart_vm_precompiled_runtime") {
+  configs += ["..:dart_config_no_precompiler"]
+  public_configs = [":libdart_vm_config"]
+  defines = ["DART_PRECOMPILED_RUNTIME"]
+  vm_sources_list = exec_script("../../tools/gypi_to_gn.py",
+                                [rebase_path("vm_sources.gypi")],
+                                "scope",
+                                ["vm_sources.gypi"])
+
+  set_sources_assignment_filter(["*_test.cc", "*_test.h"])
+  sources = vm_sources_list.sources
   include_dirs = [
     "..",
   ]
@@ -73,7 +89,6 @@
 
   set_sources_assignment_filter(["*_test.cc", "*_test.h"])
   sources = vm_sources_list.sources
-            - ["vtune.cc", "vtune.h"]
   include_dirs = [
     "..",
   ]
@@ -179,6 +194,14 @@
       "..",
     ]
   }
+  static_library("libdart_lib_precompiled_runtime") {
+    configs += ["..:dart_config_no_precompiler"]
+    defines = ["DART_PRECOMPILED_RUNTIME"]
+    sources = libsources + [ "bootstrap_nocore.cc", ]
+    include_dirs = [
+      "..",
+    ]
+  }
 }
 
 
diff --git a/runtime/vm/aot_optimizer.cc b/runtime/vm/aot_optimizer.cc
index 63c13f5..f813eb8 100644
--- a/runtime/vm/aot_optimizer.cc
+++ b/runtime/vm/aot_optimizer.cc
@@ -29,8 +29,6 @@
 
 namespace dart {
 
-DECLARE_FLAG(bool, precompilation);
-
 // Quick access to the current isolate and zone.
 #define I (isolate())
 #define Z (zone())
@@ -260,7 +258,7 @@
 
 
 const ICData& AotOptimizer::TrySpecializeICData(const ICData& ic_data,
-                                                      intptr_t cid) {
+                                                intptr_t cid) {
   ASSERT(ic_data.NumArgsTested() == 1);
 
   if ((ic_data.NumberOfUsedChecks() == 1) && ic_data.HasReceiverClassId(cid)) {
@@ -375,9 +373,9 @@
 
 
 void AotOptimizer::AppendExtractNthOutputForMerged(Definition* instr,
-                                                         intptr_t index,
-                                                         Representation rep,
-                                                         intptr_t cid) {
+                                                   intptr_t index,
+                                                   Representation rep,
+                                                   intptr_t cid) {
   ExtractNthOutputInstr* extract =
       new(Z) ExtractNthOutputInstr(new(Z) Value(instr), index, rep, cid);
   instr->ReplaceUsesWith(extract);
@@ -711,7 +709,7 @@
 
 
 void AotOptimizer::ReplaceCall(Definition* call,
-                                     Definition* replacement) {
+                               Definition* replacement) {
   // Remove the original push arguments.
   for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
     PushArgumentInstr* push = call->PushArgumentAt(i);
@@ -723,9 +721,9 @@
 
 
 void AotOptimizer::AddCheckSmi(Definition* to_check,
-                                     intptr_t deopt_id,
-                                     Environment* deopt_environment,
-                                     Instruction* insert_before) {
+                               intptr_t deopt_id,
+                               Environment* deopt_environment,
+                               Instruction* insert_before) {
   if (to_check->Type()->ToCid() != kSmiCid) {
     InsertBefore(insert_before,
                  new(Z) CheckSmiInstr(new(Z) Value(to_check),
@@ -738,9 +736,9 @@
 
 
 Instruction* AotOptimizer::GetCheckClass(Definition* to_check,
-                                               const ICData& unary_checks,
-                                               intptr_t deopt_id,
-                                               TokenPosition token_pos) {
+                                         const ICData& unary_checks,
+                                         intptr_t deopt_id,
+                                         TokenPosition token_pos) {
   if ((unary_checks.NumberOfUsedChecks() == 1) &&
       unary_checks.HasReceiverClassId(kSmiCid)) {
     return new(Z) CheckSmiInstr(new(Z) Value(to_check),
@@ -753,10 +751,10 @@
 
 
 void AotOptimizer::AddCheckClass(Definition* to_check,
-                                       const ICData& unary_checks,
-                                       intptr_t deopt_id,
-                                       Environment* deopt_environment,
-                                       Instruction* insert_before) {
+                                 const ICData& unary_checks,
+                                 intptr_t deopt_id,
+                                 Environment* deopt_environment,
+                                 Instruction* insert_before) {
   // Type propagation has not run yet, we cannot eliminate the check.
   Instruction* check = GetCheckClass(
       to_check, unary_checks, deopt_id, insert_before->token_pos());
@@ -823,7 +821,7 @@
 // E.g., detect str[x] == "x"; and use an integer comparison of char-codes.
 // TODO(srdjan): Expand for two-byte and external strings.
 bool AotOptimizer::TryStringLengthOneEquality(InstanceCallInstr* call,
-                                                    Token::Kind op_kind) {
+                                              Token::Kind op_kind) {
   ASSERT(HasOnlyTwoOf(*call->ic_data(), kOneByteStringCid));
   // Check that left and right are length one strings (either string constants
   // or results of string-from-char-code.
@@ -910,7 +908,7 @@
 static bool SmiFitsInDouble() { return kSmiBits < 53; }
 
 bool AotOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call,
-                                                  Token::Kind op_kind) {
+                                            Token::Kind op_kind) {
   const ICData& ic_data = *call->ic_data();
   ASSERT(ic_data.NumArgsTested() == 2);
 
@@ -1019,7 +1017,7 @@
 
 
 bool AotOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call,
-                                                    Token::Kind op_kind) {
+                                              Token::Kind op_kind) {
   const ICData& ic_data = *call->ic_data();
   ASSERT(ic_data.NumArgsTested() == 2);
 
@@ -1081,7 +1079,7 @@
 
 
 bool AotOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call,
-                                                Token::Kind op_kind) {
+                                          Token::Kind op_kind) {
   intptr_t operands_type = kIllegalCid;
   ASSERT(call->HasICData());
   const ICData& ic_data = *call->ic_data();
@@ -1290,7 +1288,7 @@
 
 
 bool AotOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call,
-                                               Token::Kind op_kind) {
+                                         Token::Kind op_kind) {
   ASSERT(call->ArgumentCount() == 1);
   Definition* input = call->ArgumentAt(0);
   Definition* unary_op = NULL;
@@ -1325,7 +1323,7 @@
 
 // Using field class
 RawField* AotOptimizer::GetField(intptr_t class_id,
-                                       const String& field_name) {
+                                 const String& field_name) {
   Class& cls = Class::Handle(Z, isolate()->class_table()->At(class_id));
   Field& field = Field::Handle(Z);
   while (!cls.IsNull()) {
@@ -1373,8 +1371,7 @@
 }
 
 
-bool AotOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call,
-                                                      bool allow_check) {
+bool AotOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) {
   ASSERT(call->HasICData());
   const ICData& ic_data = *call->ic_data();
   ASSERT(ic_data.HasOneTarget());
@@ -1389,10 +1386,7 @@
   ASSERT(!field.IsNull());
 
   if (InstanceCallNeedsClassCheck(call, RawFunction::kImplicitGetter)) {
-    if (!allow_check) {
-      return false;
-    }
-    AddReceiverCheck(call);
+    return false;
   }
   LoadFieldInstr* load = new(Z) LoadFieldInstr(
       new(Z) Value(call->ArgumentAt(0)),
@@ -1419,7 +1413,7 @@
 
 
 bool AotOptimizer::InlineFloat32x4Getter(InstanceCallInstr* call,
-                                               MethodRecognizer::Kind getter) {
+                                         MethodRecognizer::Kind getter) {
   if (!ShouldInlineSimd()) {
     return false;
   }
@@ -1494,7 +1488,7 @@
 
 
 bool AotOptimizer::InlineFloat64x2Getter(InstanceCallInstr* call,
-                                               MethodRecognizer::Kind getter) {
+                                         MethodRecognizer::Kind getter) {
   if (!ShouldInlineSimd()) {
     return false;
   }
@@ -1520,7 +1514,7 @@
 
 
 bool AotOptimizer::InlineInt32x4Getter(InstanceCallInstr* call,
-                                              MethodRecognizer::Kind getter) {
+                                       MethodRecognizer::Kind getter) {
   if (!ShouldInlineSimd()) {
     return false;
   }
@@ -1595,7 +1589,7 @@
 
 
 bool AotOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call,
-                                                 Token::Kind op_kind) {
+                                           Token::Kind op_kind) {
   if (!ShouldInlineSimd()) {
     return false;
   }
@@ -1628,7 +1622,7 @@
 
 
 bool AotOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call,
-                                                Token::Kind op_kind) {
+                                         Token::Kind op_kind) {
   if (!ShouldInlineSimd()) {
     return false;
   }
@@ -1660,7 +1654,7 @@
 
 
 bool AotOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call,
-                                                 Token::Kind op_kind) {
+                                           Token::Kind op_kind) {
   if (!ShouldInlineSimd()) {
     return false;
   }
@@ -1692,9 +1686,7 @@
 
 
 // Only unique implicit instance getters can be currently handled.
-// Returns false if 'allow_check' is false and a check is needed.
-bool AotOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call,
-                                                 bool allow_check) {
+bool AotOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) {
   ASSERT(call->HasICData());
   const ICData& ic_data = *call->ic_data();
   if (ic_data.NumberOfUsedChecks() == 0) {
@@ -1714,7 +1706,7 @@
     // inlining in FlowGraphInliner.
     return false;
   }
-  return InlineImplicitInstanceGetter(call, allow_check);
+  return InlineImplicitInstanceGetter(call);
 }
 
 
@@ -2040,7 +2032,7 @@
     StaticCallInstr* call,
     MethodRecognizer::Kind recognized_kind) {
   // Cannot handle unboxed instructions.
-  ASSERT(FLAG_precompilation);
+  ASSERT(FLAG_precompiled_mode);
   return false;
 }
 
@@ -2049,7 +2041,7 @@
     StaticCallInstr* call,
     MethodRecognizer::Kind recognized_kind) {
   // Cannot handle unboxed instructions.
-  ASSERT(FLAG_precompilation);
+  ASSERT(FLAG_precompiled_mode);
   return false;
 }
 
@@ -2058,7 +2050,7 @@
     StaticCallInstr* call,
     MethodRecognizer::Kind recognized_kind) {
   // Cannot handle unboxed instructions.
-  ASSERT(FLAG_precompilation);
+  ASSERT(FLAG_precompiled_mode);
   return false;
 }
 
@@ -2431,14 +2423,14 @@
   }
 
   if ((op_kind == Token::kGET) &&
-      TryInlineInstanceGetter(instr, false /* no checks allowed */)) {
+      TryInlineInstanceGetter(instr)) {
     return;
   }
   const ICData& unary_checks =
       ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks());
   if ((unary_checks.NumberOfChecks() > 0) &&
       (op_kind == Token::kSET) &&
-      TryInlineInstanceSetter(instr, unary_checks, false /* no checks */)) {
+      TryInlineInstanceSetter(instr, unary_checks)) {
     return;
   }
 
@@ -2555,7 +2547,7 @@
 // Tries to optimize instance call by replacing it with a faster instruction
 // (e.g, binary op, field load, ..).
 void AotOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
-  ASSERT(FLAG_precompilation);
+  ASSERT(FLAG_precompiled_mode);
   InstanceCallNoopt(instr);
 }
 
@@ -2582,7 +2574,7 @@
       break;
   }
   if (unary_kind != MathUnaryInstr::kIllegal) {
-    ASSERT(FLAG_precompilation);
+    ASSERT(FLAG_precompiled_mode);
     // TODO(srdjan): Adapt MathUnaryInstr to allow tagged inputs as well.
     return;
   }
@@ -2662,7 +2654,7 @@
     case MethodRecognizer::kMathAcos:
     case MethodRecognizer::kMathAtan:
     case MethodRecognizer::kMathAtan2: {
-      ASSERT(FLAG_precompilation);
+      ASSERT(FLAG_precompiled_mode);
       // No UnboxDouble instructions allowed.
       return;
     }
@@ -2765,11 +2757,10 @@
 
 
 bool AotOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr,
-                                                 const ICData& unary_ic_data,
-                                                 bool allow_checks) {
+                                           const ICData& unary_ic_data) {
   ASSERT((unary_ic_data.NumberOfChecks() > 0) &&
       (unary_ic_data.NumArgsTested() == 1));
-  if (I->flags().type_checks()) {
+  if (I->type_checks()) {
     // Checked mode setters are inlined like normal methods by conventional
     // inlining.
     return false;
@@ -2800,35 +2791,7 @@
   ASSERT(!field.IsNull());
 
   if (InstanceCallNeedsClassCheck(instr, RawFunction::kImplicitSetter)) {
-    if (!allow_checks) {
-      return false;
-    }
-    AddReceiverCheck(instr);
-  }
-  if (field.guarded_cid() != kDynamicCid) {
-    if (!allow_checks) {
-      return false;
-    }
-    InsertBefore(instr,
-                 new(Z) GuardFieldClassInstr(
-                     new(Z) Value(instr->ArgumentAt(1)),
-                      field,
-                      instr->deopt_id()),
-                 instr->env(),
-                 FlowGraph::kEffect);
-  }
-
-  if (field.needs_length_check()) {
-    if (!allow_checks) {
-      return false;
-    }
-    InsertBefore(instr,
-                 new(Z) GuardFieldLengthInstr(
-                     new(Z) Value(instr->ArgumentAt(1)),
-                      field,
-                      instr->deopt_id()),
-                 instr->env(),
-                 FlowGraph::kEffect);
+    return false;
   }
 
   // Field guard was detached.
diff --git a/runtime/vm/aot_optimizer.h b/runtime/vm/aot_optimizer.h
index e770ffe..3d1ed1b 100644
--- a/runtime/vm/aot_optimizer.h
+++ b/runtime/vm/aot_optimizer.h
@@ -74,11 +74,9 @@
   bool TryReplaceWithEqualityOp(InstanceCallInstr* call, Token::Kind op_kind);
   bool TryReplaceWithRelationalOp(InstanceCallInstr* call, Token::Kind op_kind);
 
-  bool TryInlineInstanceGetter(InstanceCallInstr* call,
-                               bool allow_check = true);
+  bool TryInlineInstanceGetter(InstanceCallInstr* call);
   bool TryInlineInstanceSetter(InstanceCallInstr* call,
-                               const ICData& unary_ic_data,
-                               bool allow_check = true);
+                               const ICData& unary_ic_data);
 
   bool TryInlineInstanceMethod(InstanceCallInstr* call);
   bool TryInlineFloat32x4Constructor(StaticCallInstr* call,
@@ -142,7 +140,7 @@
                               Token::Kind op_kind);
   bool InlineFloat64x2BinaryOp(InstanceCallInstr* call,
                                Token::Kind op_kind);
-  bool InlineImplicitInstanceGetter(InstanceCallInstr* call, bool allow_check);
+  bool InlineImplicitInstanceGetter(InstanceCallInstr* call);
 
   RawBool* InstanceOfAsBool(const ICData& ic_data,
                             const AbstractType& type,
diff --git a/runtime/vm/assembler.cc b/runtime/vm/assembler.cc
index 495419d..318881c 100644
--- a/runtime/vm/assembler.cc
+++ b/runtime/vm/assembler.cc
@@ -244,16 +244,16 @@
 
 intptr_t ObjectPoolWrapper::AddObject(const Object& obj,
                                       Patchability patchable) {
-  return AddObject(ObjectPool::Entry(&obj), patchable);
+  return AddObject(ObjectPoolWrapperEntry(&obj), patchable);
 }
 
 
 intptr_t ObjectPoolWrapper::AddImmediate(uword imm) {
-  return AddObject(ObjectPool::Entry(imm, ObjectPool::kImmediate),
+  return AddObject(ObjectPoolWrapperEntry(imm, ObjectPool::kImmediate),
                    kNotPatchable);
 }
 
-intptr_t ObjectPoolWrapper::AddObject(ObjectPool::Entry entry,
+intptr_t ObjectPoolWrapper::AddObject(ObjectPoolWrapperEntry entry,
                                       Patchability patchable) {
   object_pool_.Add(entry);
   if (patchable == kNotPatchable) {
@@ -265,7 +265,7 @@
 }
 
 
-intptr_t ObjectPoolWrapper::FindObject(ObjectPool::Entry entry,
+intptr_t ObjectPoolWrapper::FindObject(ObjectPoolWrapperEntry entry,
                                        Patchability patchable) {
   // If the object is not patchable, check if we've already got it in the
   // object pool.
@@ -282,20 +282,27 @@
 
 intptr_t ObjectPoolWrapper::FindObject(const Object& obj,
                                        Patchability patchable) {
-  return FindObject(ObjectPool::Entry(&obj), patchable);
+  return FindObject(ObjectPoolWrapperEntry(&obj), patchable);
+}
+
+
+intptr_t ObjectPoolWrapper::FindObject(const Object& obj,
+                                       const Object& equivalence) {
+  return FindObject(ObjectPoolWrapperEntry(&obj, &equivalence),
+                    kNotPatchable);
 }
 
 
 intptr_t ObjectPoolWrapper::FindImmediate(uword imm) {
-  return FindObject(ObjectPool::Entry(imm, ObjectPool::kImmediate),
+  return FindObject(ObjectPoolWrapperEntry(imm, ObjectPool::kImmediate),
                     kNotPatchable);
 }
 
 
 intptr_t ObjectPoolWrapper::FindNativeEntry(const ExternalLabel* label,
                                             Patchability patchable) {
-  return FindObject(ObjectPool::Entry(label->address(),
-                                      ObjectPool::kNativeEntry),
+  return FindObject(ObjectPoolWrapperEntry(label->address(),
+                                           ObjectPool::kNativeEntry),
                     patchable);
 }
 
diff --git a/runtime/vm/assembler.h b/runtime/vm/assembler.h
index c414c0d..5d20c01 100644
--- a/runtime/vm/assembler.h
+++ b/runtime/vm/assembler.h
@@ -212,11 +212,30 @@
 };
 
 
+struct ObjectPoolWrapperEntry {
+  ObjectPoolWrapperEntry()
+    : raw_value_(), type_(), equivalence_() { }
+  explicit ObjectPoolWrapperEntry(const Object* obj)
+    : obj_(obj), type_(ObjectPool::kTaggedObject), equivalence_(obj) { }
+  explicit ObjectPoolWrapperEntry(const Object* obj, const Object* eqv)
+    : obj_(obj), type_(ObjectPool::kTaggedObject), equivalence_(eqv) { }
+  ObjectPoolWrapperEntry(uword value, ObjectPool::EntryType info)
+    : raw_value_(value), type_(info), equivalence_() { }
+
+  union {
+    const Object* obj_;
+    uword raw_value_;
+  };
+  ObjectPool::EntryType type_;
+  const Object* equivalence_;
+};
+
+
 // Pair type parameter for DirectChainedHashMap used for the constant pool.
 class ObjIndexPair {
  public:
   // Typedefs needed for the DirectChainedHashMap template.
-  typedef ObjectPool::Entry Key;
+  typedef ObjectPoolWrapperEntry Key;
   typedef intptr_t Value;
   typedef ObjIndexPair Pair;
 
@@ -233,6 +252,11 @@
       } else {
         key_.obj_ = &Object::ZoneHandle(key.obj_->raw());
       }
+      if (key.equivalence_->IsNotTemporaryScopedHandle()) {
+        key_.equivalence_ = key.equivalence_;
+      } else {
+        key_.equivalence_ = &Object::ZoneHandle(key.equivalence_->raw());
+      }
     } else {
       key_.raw_value_ = key.raw_value_;
     }
@@ -268,7 +292,8 @@
   static inline bool IsKeyEqual(Pair kv, Key key) {
     if (kv.key_.type_ != key.type_) return false;
     if (kv.key_.type_ == ObjectPool::kTaggedObject) {
-      return kv.key_.obj_->raw() == key.obj_->raw();
+      return (kv.key_.obj_->raw() == key.obj_->raw()) &&
+             (kv.key_.equivalence_->raw() == key.equivalence_->raw());
     }
     return kv.key_.raw_value_ == key.raw_value_;
   }
@@ -293,6 +318,8 @@
 
   intptr_t FindObject(const Object& obj,
                       Patchability patchable = kNotPatchable);
+  intptr_t FindObject(const Object& obj,
+                      const Object& equivalence);
   intptr_t FindImmediate(uword imm);
   intptr_t FindNativeEntry(const ExternalLabel* label,
                            Patchability patchable);
@@ -300,11 +327,11 @@
   RawObjectPool* MakeObjectPool();
 
  private:
-  intptr_t AddObject(ObjectPool::Entry entry, Patchability patchable);
-  intptr_t FindObject(ObjectPool::Entry entry, Patchability patchable);
+  intptr_t AddObject(ObjectPoolWrapperEntry entry, Patchability patchable);
+  intptr_t FindObject(ObjectPoolWrapperEntry entry, Patchability patchable);
 
   // Objects and jump targets.
-  GrowableArray<ObjectPool::Entry> object_pool_;
+  GrowableArray<ObjectPoolWrapperEntry> object_pool_;
 
   // Hashmap for fast lookup in object pool.
   DirectChainedHashMap<ObjIndexPair> object_pool_index_table_;
diff --git a/runtime/vm/assembler_arm.cc b/runtime/vm/assembler_arm.cc
index e74a8c8..4043fc1 100644
--- a/runtime/vm/assembler_arm.cc
+++ b/runtime/vm/assembler_arm.cc
@@ -21,12 +21,9 @@
 
 namespace dart {
 
-DECLARE_FLAG(bool, allow_absolute_addresses);
 DECLARE_FLAG(bool, check_code_pointer);
 DECLARE_FLAG(bool, inline_alloc);
 
-DEFINE_FLAG(bool, print_stop_message, true, "Print stop message.");
-
 uint32_t Address::encoding3() const {
   if (kind_ == Immediate) {
     uint32_t offset = encoding_ & kOffset12Mask;
@@ -1568,6 +1565,7 @@
 
 bool Assembler::CanLoadFromObjectPool(const Object& object) const {
   ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+  ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
   ASSERT(!Thread::CanLoadFromThread(object));
   if (!constant_pool_allowed()) {
     return false;
@@ -1585,6 +1583,7 @@
                                  bool is_unique,
                                  Register pp) {
   ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+  ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
   // Load common VM constants from the thread. This works also in places where
   // no constant pool is set up (e.g. intrinsic code).
   if (Thread::CanLoadFromThread(object)) {
@@ -1644,6 +1643,7 @@
 
 void Assembler::PushObject(const Object& object) {
   ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+  ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
   LoadObject(IP, object);
   Push(IP);
 }
@@ -1651,6 +1651,7 @@
 
 void Assembler::CompareObject(Register rn, const Object& object) {
   ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+  ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
   ASSERT(rn != IP);
   if (object.IsSmi()) {
     CompareImmediate(rn, reinterpret_cast<int32_t>(object.raw()));
@@ -1910,6 +1911,7 @@
                                          const Object& value,
                                          FieldContent old_content) {
   ASSERT(!value.IsICData() || ICData::Cast(value).IsOriginal());
+  ASSERT(!value.IsField() || Field::Cast(value).IsOriginal());
   ASSERT(value.IsSmi() || value.InVMHeap() ||
          (value.IsOld() && value.IsNotTemporaryScopedHandle()));
   // No store buffer update.
@@ -1923,6 +1925,7 @@
                                                const Object& value,
                                                FieldContent old_content) {
   ASSERT(!value.IsICData() || ICData::Cast(value).IsOriginal());
+  ASSERT(!value.IsField() || Field::Cast(value).IsOriginal());
   int32_t ignored = 0;
   if (Address::CanHoldStoreOffset(kWord, offset - kHeapObjectTag, &ignored)) {
     StoreIntoObjectNoBarrier(object, FieldAddress(object, offset), value,
@@ -2751,6 +2754,21 @@
 }
 
 
+void Assembler::BranchLinkWithEquivalence(const StubEntry& stub_entry,
+                                          const Object& equivalence) {
+  const Code& target = Code::Handle(stub_entry.code());
+  // Make sure that class CallPattern is able to patch the label referred
+  // to by this code sequence.
+  // For added code robustness, use 'blx lr' in a patchable sequence and
+  // use 'blx ip' in a non-patchable sequence (see other BranchLink flavors).
+  const int32_t offset = ObjectPool::element_offset(
+      object_pool_wrapper_.FindObject(target, equivalence));
+  LoadWordFromPoolOffset(CODE_REG, offset - kHeapObjectTag, PP, AL);
+  ldr(LR, FieldAddress(CODE_REG, Code::entry_point_offset()));
+  blx(LR);  // Use blx instruction so that the return branch prediction works.
+}
+
+
 void Assembler::BranchLink(const ExternalLabel* label) {
   LoadImmediate(LR, label->address());  // Target address is never patched.
   blx(LR);  // Use blx instruction so that the return branch prediction works.
diff --git a/runtime/vm/assembler_arm.h b/runtime/vm/assembler_arm.h
index 80b888b..b3014fb 100644
--- a/runtime/vm/assembler_arm.h
+++ b/runtime/vm/assembler_arm.h
@@ -680,6 +680,11 @@
   void BranchLinkPatchable(const StubEntry& stub_entry);
   void BranchLinkPatchable(const Code& code);
 
+  // Emit a call that shares its object pool entries with other calls
+  // that have the same equivalence marker.
+  void BranchLinkWithEquivalence(const StubEntry& stub_entry,
+                                 const Object& equivalence);
+
   // Branch and link to [base + offset]. Call sequence is never patched.
   void BranchLinkOffset(Register base, int32_t offset);
 
diff --git a/runtime/vm/assembler_arm64.cc b/runtime/vm/assembler_arm64.cc
index 59c85c3..70b2f2c 100644
--- a/runtime/vm/assembler_arm64.cc
+++ b/runtime/vm/assembler_arm64.cc
@@ -21,12 +21,10 @@
 
 namespace dart {
 
-DECLARE_FLAG(bool, allow_absolute_addresses);
 DECLARE_FLAG(bool, check_code_pointer);
 DECLARE_FLAG(bool, inline_alloc);
 
 DEFINE_FLAG(bool, use_far_branches, false, "Always use far branches");
-DEFINE_FLAG(bool, print_stop_message, false, "Print stop message.");
 
 
 Assembler::Assembler(bool use_far_branches)
@@ -370,6 +368,7 @@
 
 bool Assembler::CanLoadFromObjectPool(const Object& object) const {
   ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+  ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
   ASSERT(!Thread::CanLoadFromThread(object));
   if (!constant_pool_allowed()) {
     return false;
@@ -405,6 +404,7 @@
                                  const Object& object,
                                  bool is_unique) {
   ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+  ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
   if (Thread::CanLoadFromThread(object)) {
     ldr(dst, Address(THR, Thread::OffsetFromThread(object)));
   } else if (CanLoadFromObjectPool(object)) {
@@ -444,6 +444,7 @@
 
 void Assembler::CompareObject(Register reg, const Object& object) {
   ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+  ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
   if (Thread::CanLoadFromThread(object)) {
     ldr(TMP, Address(THR, Thread::OffsetFromThread(object)));
     CompareRegisters(reg, TMP);
@@ -611,6 +612,17 @@
 }
 
 
+void Assembler::BranchLinkWithEquivalence(const StubEntry& stub_entry,
+                                          const Object& equivalence) {
+  const Code& target = Code::Handle(stub_entry.code());
+  const int32_t offset = ObjectPool::element_offset(
+      object_pool_wrapper_.FindObject(target, equivalence));
+  LoadWordFromPoolOffset(CODE_REG, offset);
+  ldr(TMP, FieldAddress(CODE_REG, Code::entry_point_offset()));
+  blr(TMP);
+}
+
+
 void Assembler::AddImmediate(Register dest, Register rn, int64_t imm) {
   Operand op;
   if (imm == 0) {
@@ -939,6 +951,7 @@
                                          const Address& dest,
                                          const Object& value) {
   ASSERT(!value.IsICData() || ICData::Cast(value).IsOriginal());
+  ASSERT(!value.IsField() || Field::Cast(value).IsOriginal());
   ASSERT(value.IsSmi() || value.InVMHeap() ||
          (value.IsOld() && value.IsNotTemporaryScopedHandle()));
   // No store buffer update.
diff --git a/runtime/vm/assembler_arm64.h b/runtime/vm/assembler_arm64.h
index ffb6b768..1475625 100644
--- a/runtime/vm/assembler_arm64.h
+++ b/runtime/vm/assembler_arm64.h
@@ -757,6 +757,22 @@
     EmitLoadStoreRegPair(STP, rt, rt2, a, sz);
   }
 
+  void ldxr(Register rt, Register rn) {
+    // rt = value
+    // rn = address
+    EmitLoadStoreExclusive(LDXR, R31, rn, rt, kDoubleWord);
+  }
+  void stxr(Register rs, Register rt, Register rn) {
+    // rs = status (1 = failure, 0 = success)
+    // rt = value
+    // rn = address
+    EmitLoadStoreExclusive(STXR, rs, rn, rt, kDoubleWord);
+  }
+  void clrex() {
+    const int32_t encoding = static_cast<int32_t>(CLREX);
+    Emit(encoding);
+  }
+
   // Conditional select.
   void csel(Register rd, Register rn, Register rm, Condition cond) {
     EmitConditionalSelect(CSEL, rd, rn, rm, cond, kDoubleWord);
@@ -1213,6 +1229,11 @@
 
   void BranchLinkPatchable(const StubEntry& stub_entry);
 
+  // Emit a call that shares its object pool entries with other calls
+  // that have the same equivalence marker.
+  void BranchLinkWithEquivalence(const StubEntry& stub_entry,
+                                 const Object& equivalence);
+
   // Macros accepting a pp Register argument may attempt to load values from
   // the object pool when possible. Unless you are sure that the untagged object
   // pool pointer is in another register, or that it is not available at all,
@@ -1714,6 +1735,24 @@
     Emit(encoding);
   }
 
+  void EmitLoadStoreExclusive(LoadStoreExclusiveOp op, Register rs, Register rn,
+                              Register rt, OperandSize sz = kDoubleWord) {
+    ASSERT(sz == kDoubleWord);
+    const int32_t size = B31 | B30;
+
+    ASSERT((rs != kNoRegister) && (rs != ZR));
+    ASSERT((rn != kNoRegister) && (rn != ZR));
+    ASSERT((rt != kNoRegister) && (rt != ZR));
+
+    const int32_t encoding =
+        op | size |
+        (static_cast<int32_t>(ConcreteRegister(rs)) << kRsShift) |
+        (static_cast<int32_t>(ConcreteRegister(rn)) << kRnShift) |
+        (static_cast<int32_t>(ConcreteRegister(rt)) << kRtShift);
+
+    Emit(encoding);
+  }
+
   void EmitLoadStoreReg(LoadStoreRegOp op, Register rt, Address a,
                         OperandSize sz) {
     const Register crt = ConcreteRegister(rt);
diff --git a/runtime/vm/assembler_arm64_test.cc b/runtime/vm/assembler_arm64_test.cc
index 9320421..d27358e 100644
--- a/runtime/vm/assembler_arm64_test.cc
+++ b/runtime/vm/assembler_arm64_test.cc
@@ -563,6 +563,52 @@
 }
 
 
+ASSEMBLER_TEST_GENERATE(Semaphore, assembler) {
+  __ SetupDartSP(kTestStackSpace);
+  __ movz(R0, Immediate(40), 0);
+  __ movz(R1, Immediate(42), 0);
+  __ Push(R0);
+  Label retry;
+  __ Bind(&retry);
+  __ ldxr(R0, SP);
+  __ stxr(TMP, R1, SP);  // IP == 0, success
+  __ cmp(TMP, Operand(0));
+  __ b(&retry, NE);  // NE if context switch occurred between ldrex and strex.
+  __ Pop(R0);  // 42
+  __ mov(CSP, SP);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(Semaphore, test) {
+  EXPECT(test != NULL);
+  typedef int (*Semaphore)() DART_UNUSED;
+  EXPECT_EQ(42, EXECUTE_TEST_CODE_INT64(Semaphore, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(FailedSemaphore, assembler) {
+  __ SetupDartSP(kTestStackSpace);
+  __ movz(R0, Immediate(40), 0);
+  __ movz(R1, Immediate(42), 0);
+  __ Push(R0);
+  __ ldxr(R0, SP);
+  __ clrex();  // Simulate a context switch.
+  __ stxr(TMP, R1, SP);  // IP == 1, failure
+  __ Pop(R0);  // 40
+  __ add(R0, R0, Operand(TMP));
+  __ mov(CSP, SP);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(FailedSemaphore, test) {
+  EXPECT(test != NULL);
+  typedef int (*FailedSemaphore)() DART_UNUSED;
+  EXPECT_EQ(41, EXECUTE_TEST_CODE_INT64(FailedSemaphore, test->entry()));
+}
+
+
 // Logical register operations.
 ASSEMBLER_TEST_GENERATE(AndRegs, assembler) {
   __ movz(R1, Immediate(43), 0);
diff --git a/runtime/vm/assembler_ia32.cc b/runtime/vm/assembler_ia32.cc
index 8d3fb09..2759cd2 100644
--- a/runtime/vm/assembler_ia32.cc
+++ b/runtime/vm/assembler_ia32.cc
@@ -18,7 +18,6 @@
 
 namespace dart {
 
-DEFINE_FLAG(bool, print_stop_message, true, "Print stop message.");
 DECLARE_FLAG(bool, inline_alloc);
 
 
@@ -2164,6 +2163,7 @@
 
 void Assembler::LoadObject(Register dst, const Object& object) {
   ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+  ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
   if (object.IsSmi() || object.InVMHeap()) {
     movl(dst, Immediate(reinterpret_cast<int32_t>(object.raw())));
   } else {
@@ -2178,6 +2178,7 @@
 
 void Assembler::LoadObjectSafely(Register dst, const Object& object) {
   ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+  ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
   if (Assembler::IsSafe(object)) {
     LoadObject(dst, object);
   } else {
@@ -2190,6 +2191,7 @@
 
 void Assembler::PushObject(const Object& object) {
   ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+  ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
   if (object.IsSmi() || object.InVMHeap()) {
     pushl(Immediate(reinterpret_cast<int32_t>(object.raw())));
   } else {
@@ -2204,6 +2206,7 @@
 
 void Assembler::CompareObject(Register reg, const Object& object) {
   ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+  ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
   if (object.IsSmi() || object.InVMHeap()) {
     cmpl(reg, Immediate(reinterpret_cast<int32_t>(object.raw())));
   } else {
@@ -2403,6 +2406,7 @@
 void Assembler::UnverifiedStoreOldObject(const Address& dest,
                                          const Object& value) {
   ASSERT(!value.IsICData() || ICData::Cast(value).IsOriginal());
+  ASSERT(!value.IsField() || Field::Cast(value).IsOriginal());
   ASSERT(value.IsOld());
   ASSERT(!value.InVMHeap());
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
@@ -2417,6 +2421,7 @@
                                          const Object& value,
                                          FieldContent old_content) {
   ASSERT(!value.IsICData() || ICData::Cast(value).IsOriginal());
+  ASSERT(!value.IsField() || Field::Cast(value).IsOriginal());
   VerifyHeapWord(dest, old_content);
   if (value.IsSmi() || value.InVMHeap()) {
     Immediate imm_value(reinterpret_cast<int32_t>(value.raw()));
diff --git a/runtime/vm/assembler_mips.cc b/runtime/vm/assembler_mips.cc
index 957b549..f5cbd1a 100644
--- a/runtime/vm/assembler_mips.cc
+++ b/runtime/vm/assembler_mips.cc
@@ -14,15 +14,12 @@
 
 namespace dart {
 
-DECLARE_FLAG(bool, allow_absolute_addresses);
 DECLARE_FLAG(bool, check_code_pointer);
 DECLARE_FLAG(bool, inline_alloc);
 #if defined(USING_SIMULATOR)
 DECLARE_FLAG(int, trace_sim_after);
 #endif
 
-DEFINE_FLAG(bool, print_stop_message, false, "Print stop message.");
-
 void Assembler::InitializeMemoryWithBreakpoints(uword data, intptr_t length) {
   ASSERT(Utils::IsAligned(data, 4));
   ASSERT(Utils::IsAligned(length, 4));
@@ -536,8 +533,22 @@
 }
 
 
+void Assembler::BranchLinkWithEquivalence(const StubEntry& stub_entry,
+                                          const Object& equivalence) {
+  const Code& target = Code::Handle(stub_entry.code());
+  ASSERT(!in_delay_slot_);
+  const int32_t offset = ObjectPool::element_offset(
+      object_pool_wrapper_.FindObject(target, equivalence));
+  LoadWordFromPoolOffset(CODE_REG, offset - kHeapObjectTag);
+  lw(T9, FieldAddress(CODE_REG, Code::entry_point_offset()));
+  jalr(T9);
+  delay_slot_available_ = false;  // CodePatcher expects a nop.
+}
+
+
 bool Assembler::CanLoadFromObjectPool(const Object& object) const {
   ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+  ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
   ASSERT(!Thread::CanLoadFromThread(object));
   if (!constant_pool_allowed()) {
     return false;
@@ -553,6 +564,7 @@
                                  const Object& object,
                                  bool is_unique) {
   ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+  ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
   ASSERT(!in_delay_slot_);
   if (Thread::CanLoadFromThread(object)) {
     // Load common VM constants from the thread. This works also in places where
@@ -611,6 +623,7 @@
 
 void Assembler::PushObject(const Object& object) {
   ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+  ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
   ASSERT(!in_delay_slot_);
   LoadObject(TMP, object);
   Push(TMP);
@@ -738,6 +751,7 @@
                                          const Address& dest,
                                          const Object& value) {
   ASSERT(!value.IsICData() || ICData::Cast(value).IsOriginal());
+  ASSERT(!value.IsField() || Field::Cast(value).IsOriginal());
   ASSERT(!in_delay_slot_);
   ASSERT(value.IsSmi() || value.InVMHeap() ||
          (value.IsOld() && value.IsNotTemporaryScopedHandle()));
diff --git a/runtime/vm/assembler_mips.h b/runtime/vm/assembler_mips.h
index 382d833..1654ac9 100644
--- a/runtime/vm/assembler_mips.h
+++ b/runtime/vm/assembler_mips.h
@@ -663,6 +663,10 @@
     EmitLoadStore(LHU, rt, addr);
   }
 
+  void ll(Register rt, const Address& addr) {
+    EmitLoadStore(LL, rt, addr);
+  }
+
   void lui(Register rt, const Immediate& imm) {
     ASSERT(Utils::IsUint(kImmBits, imm.value()));
     const uint16_t imm_value = static_cast<uint16_t>(imm.value());
@@ -791,6 +795,11 @@
     EmitLoadStore(SB, rt, addr);
   }
 
+  // rt = 1 on success, 0 on failure.
+  void sc(Register rt, const Address& addr) {
+    EmitLoadStore(SC, rt, addr);
+  }
+
   void sdc1(DRegister dt, const Address& addr) {
     FRegister ft = static_cast<FRegister>(dt * 2);
     EmitFpuLoadStore(SDC1, ft, addr);
@@ -926,6 +935,11 @@
 
   void BranchLinkPatchable(const StubEntry& stub_entry);
 
+  // Emit a call that shares its object pool entries with other calls
+  // that have the same equivalence marker.
+  void BranchLinkWithEquivalence(const StubEntry& stub_entry,
+                                 const Object& equivalence);
+
   void Drop(intptr_t stack_elements) {
     ASSERT(stack_elements >= 0);
     if (stack_elements > 0) {
diff --git a/runtime/vm/assembler_mips_test.cc b/runtime/vm/assembler_mips_test.cc
index f23fe93..e3cad3d 100644
--- a/runtime/vm/assembler_mips_test.cc
+++ b/runtime/vm/assembler_mips_test.cc
@@ -2169,6 +2169,30 @@
 }
 
 
+ASSEMBLER_TEST_GENERATE(Semaphore, assembler) {
+  __ EnterFrame();
+  __ LoadImmediate(T0, 40);
+  __ LoadImmediate(T1, 42);
+  __ Push(T0);
+  Label retry;
+  __ Bind(&retry);
+  __ ll(T0, Address(SP));
+  __ mov(T2, T1);
+  __ sc(T2, Address(SP));  // T1 == 1, success
+  __ LoadImmediate(T3, 1);
+  __ bne(T2, T3, &retry);  // NE if context switch occurred between ll and sc
+  __ Pop(V0);  // 42
+  __ LeaveFrameAndReturn();
+}
+
+
+ASSEMBLER_TEST_RUN(Semaphore, test) {
+  EXPECT(test != NULL);
+  typedef int (*Semaphore)() DART_UNUSED;
+  EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(Semaphore, test->entry()));
+}
+
+
 }  // namespace dart
 
 #endif  // defined TARGET_ARCH_MIPS
diff --git a/runtime/vm/assembler_x64.cc b/runtime/vm/assembler_x64.cc
index 02527fc..e80efe6 100644
--- a/runtime/vm/assembler_x64.cc
+++ b/runtime/vm/assembler_x64.cc
@@ -17,12 +17,9 @@
 
 namespace dart {
 
-DECLARE_FLAG(bool, allow_absolute_addresses);
 DECLARE_FLAG(bool, check_code_pointer);
 DECLARE_FLAG(bool, inline_alloc);
 
-DEFINE_FLAG(bool, print_stop_message, true, "Print stop message.");
-
 
 Assembler::Assembler(bool use_far_branches)
     : buffer_(),
@@ -97,6 +94,18 @@
 }
 
 
+void Assembler::CallWithEquivalence(const StubEntry& stub_entry,
+                                    const Object& equivalence) {
+  ASSERT(constant_pool_allowed());
+  const Code& target = Code::Handle(stub_entry.code());
+  const int32_t offset = ObjectPool::element_offset(
+      object_pool_wrapper_.FindObject(target, equivalence));
+  LoadWordFromPoolOffset(CODE_REG, offset - kHeapObjectTag);
+  movq(TMP, FieldAddress(CODE_REG, Code::entry_point_offset()));
+  call(TMP);
+}
+
+
 void Assembler::Call(const StubEntry& stub_entry) {
   ASSERT(constant_pool_allowed());
   const Code& target = Code::Handle(stub_entry.code());
@@ -2740,6 +2749,7 @@
 
 bool Assembler::CanLoadFromObjectPool(const Object& object) const {
   ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+  ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
   ASSERT(!Thread::CanLoadFromThread(object));
   if (!constant_pool_allowed()) {
     return false;
@@ -2776,6 +2786,7 @@
                                  const Object& object,
                                  bool is_unique) {
   ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+  ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
   if (Thread::CanLoadFromThread(object)) {
     movq(dst, Address(THR, Thread::OffsetFromThread(object)));
   } else if (CanLoadFromObjectPool(object)) {
@@ -2814,6 +2825,7 @@
 
 void Assembler::StoreObject(const Address& dst, const Object& object) {
   ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+  ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
   if (Thread::CanLoadFromThread(object)) {
     movq(TMP, Address(THR, Thread::OffsetFromThread(object)));
     movq(dst, TMP);
@@ -2829,6 +2841,7 @@
 
 void Assembler::PushObject(const Object& object) {
   ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+  ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
   if (Thread::CanLoadFromThread(object)) {
     pushq(Address(THR, Thread::OffsetFromThread(object)));
   } else if (CanLoadFromObjectPool(object)) {
@@ -2843,6 +2856,7 @@
 
 void Assembler::CompareObject(Register reg, const Object& object) {
   ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+  ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
   if (Thread::CanLoadFromThread(object)) {
     cmpq(reg, Address(THR, Thread::OffsetFromThread(object)));
   } else if (CanLoadFromObjectPool(object)) {
@@ -3070,6 +3084,7 @@
                                          const Object& value,
                                          FieldContent old_content) {
   ASSERT(!value.IsICData() || ICData::Cast(value).IsOriginal());
+  ASSERT(!value.IsField() || Field::Cast(value).IsOriginal());
   VerifyHeapWord(dest, old_content);
   if (VerifiedMemory::enabled()) {
     const Register temp = RCX;
diff --git a/runtime/vm/assembler_x64.h b/runtime/vm/assembler_x64.h
index 30feb10..95c474b 100644
--- a/runtime/vm/assembler_x64.h
+++ b/runtime/vm/assembler_x64.h
@@ -773,6 +773,10 @@
   void J(Condition condition, const StubEntry& stub_entry, Register pp);
   void CallPatchable(const StubEntry& stub_entry);
   void Call(const StubEntry& stub_entry);
+  // Emit a call that shares its object pool entries with other calls
+  // that have the same equivalence marker.
+  void CallWithEquivalence(const StubEntry& stub_entry,
+                           const Object& equivalence);
   // Unaware of write barrier (use StoreInto* methods for storing to objects).
   // TODO(koda): Add StackAddress/HeapAddress types to prevent misuse.
   void StoreObject(const Address& dst, const Object& obj);
diff --git a/runtime/vm/ast.cc b/runtime/vm/ast.cc
index ef8d4cc..bb1b624 100644
--- a/runtime/vm/ast.cc
+++ b/runtime/vm/ast.cc
@@ -19,7 +19,7 @@
 #define DEFINE_VISIT_FUNCTION(BaseName)                                        \
 void BaseName##Node::Visit(AstNodeVisitor* visitor) {                          \
   if (FLAG_trace_ast_visitor) {                                                \
-    THR_Print("Visiting %s\n", PrettyName());                                  \
+    THR_Print("Visiting %s\n", Name());                                        \
   }                                                                            \
   visitor->Visit##BaseName##Node(this);                                        \
 }
@@ -29,7 +29,7 @@
 
 
 #define DEFINE_NAME_FUNCTION(BaseName)                                         \
-const char* BaseName##Node::PrettyName() const {                               \
+const char* BaseName##Node::Name() const {                                     \
   return #BaseName;                                                            \
 }
 
@@ -37,6 +37,17 @@
 #undef DEFINE_NAME_FUNCTION
 
 
+const Field* AstNode::MayCloneField(const Field& value) {
+  if (Compiler::IsBackgroundCompilation() ||
+      FLAG_force_clone_compiler_objects) {
+    return &Field::ZoneHandle(value.CloneFromOriginal());
+  } else {
+    ASSERT(value.IsZoneHandle());
+    return &value;
+  }
+}
+
+
 // A visitor class to collect all the nodes (including children) into an
 // array.
 class AstNodeCollector : public AstNodeVisitor {
@@ -575,14 +586,15 @@
   if (field().is_final()) {
     return NULL;
   }
-  if (Isolate::Current()->flags().type_checks()) {
+  if (Isolate::Current()->type_checks()) {
     rhs = new AssignableNode(
         field().token_pos(),
         rhs,
         AbstractType::ZoneHandle(field().type()),
         String::ZoneHandle(field().name()));
   }
-  return new StoreStaticFieldNode(token_pos(), field(), rhs);
+  return new StoreStaticFieldNode(
+      token_pos(), Field::ZoneHandle(field().Original()), rhs);
 }
 
 
@@ -663,7 +675,7 @@
     if (obj.IsField()) {
       const Field& field = Field::ZoneHandle(zone, Field::Cast(obj).raw());
       if (!field.is_final()) {
-        if (isolate->flags().type_checks()) {
+        if (isolate->type_checks()) {
           rhs = new AssignableNode(field.token_pos(),
                                    rhs,
                                    AbstractType::ZoneHandle(zone, field.type()),
@@ -698,7 +710,7 @@
     if (obj.IsField()) {
       const Field& field = Field::ZoneHandle(zone, Field::Cast(obj).raw());
       if (!field.is_final()) {
-        if (isolate->flags().type_checks()) {
+        if (isolate->type_checks()) {
           rhs = new AssignableNode(field.token_pos(),
                                    rhs,
                                    AbstractType::ZoneHandle(zone, field.type()),
@@ -754,7 +766,7 @@
     ASSERT(!getter.IsNull() &&
            (getter.kind() == RawFunction::kImplicitStaticFinalGetter));
 #endif
-    if (isolate->flags().type_checks()) {
+    if (isolate->type_checks()) {
       rhs = new AssignableNode(
           field.token_pos(),
           rhs,
diff --git a/runtime/vm/ast.h b/runtime/vm/ast.h
index f212a15..4ca2372 100644
--- a/runtime/vm/ast.h
+++ b/runtime/vm/ast.h
@@ -92,7 +92,7 @@
 
 #define DECLARE_COMMON_NODE_FUNCTIONS(type)                                    \
   virtual void Visit(AstNodeVisitor* visitor);                                 \
-  virtual const char* PrettyName() const;                                      \
+  virtual const char* Name() const;                                            \
   virtual type* As##type() { return this; }
 
 
@@ -116,7 +116,7 @@
 
   virtual void Visit(AstNodeVisitor* visitor) = 0;
   virtual void VisitChildren(AstNodeVisitor* visitor) const = 0;
-  virtual const char* PrettyName() const = 0;
+  virtual const char* Name() const = 0;
 
   // Convert the node into an assignment node using the rhs which is passed in,
   // this is typically used for converting nodes like LoadLocalNode,
@@ -150,6 +150,10 @@
   // the former).
   virtual const Instance* EvalConstExpr() const { return NULL; }
 
+  // Return ZoneHandle of a cloned 'value' when in background compilation or
+  // when testing. Otherwise return 'value' itself.
+  static const Field* MayCloneField(const Field& value);
+
  protected:
   friend class ParsedFunction;
 
@@ -1241,7 +1245,8 @@
   LoadInstanceFieldNode(TokenPosition token_pos,
                         AstNode* instance,
                         const Field& field)
-      : AstNode(token_pos), instance_(instance), field_(field) {
+      : AstNode(token_pos), instance_(instance),
+        field_(*MayCloneField(field)) {
     ASSERT(instance_ != NULL);
     ASSERT(field_.IsZoneHandle());
   }
@@ -1271,7 +1276,7 @@
                          AstNode* value)
       : AstNode(token_pos),
         instance_(instance),
-        field_(field),
+        field_(*MayCloneField(field)),
         value_(value) {
     ASSERT(instance_ != NULL);
     ASSERT(field_.IsZoneHandle());
@@ -1301,7 +1306,9 @@
 class LoadStaticFieldNode : public AstNode {
  public:
   LoadStaticFieldNode(TokenPosition token_pos, const Field& field)
-      : AstNode(token_pos), field_(field), is_deferred_reference_(false) {
+      : AstNode(token_pos),
+        field_(*MayCloneField(field)),
+        is_deferred_reference_(false) {
     ASSERT(field_.IsZoneHandle());
   }
 
@@ -1339,7 +1346,9 @@
   StoreStaticFieldNode(TokenPosition token_pos,
                        const Field& field,
                        AstNode* value)
-      : AstNode(token_pos), field_(field), value_(value) {
+      : AstNode(token_pos),
+        field_(*MayCloneField(field)),
+        value_(value) {
     ASSERT(field_.IsZoneHandle());
     ASSERT(value_ != NULL);
   }
@@ -1561,7 +1570,8 @@
 class InitStaticFieldNode : public AstNode {
  public:
   InitStaticFieldNode(TokenPosition token_pos, const Field& field)
-      : AstNode(token_pos), field_(field) {
+      : AstNode(token_pos),
+        field_(*MayCloneField(field)) {
     ASSERT(field_.IsZoneHandle());
   }
 
diff --git a/runtime/vm/ast_printer.cc b/runtime/vm/ast_printer.cc
index 3732c3a..e438827 100644
--- a/runtime/vm/ast_printer.cc
+++ b/runtime/vm/ast_printer.cc
@@ -21,7 +21,7 @@
 
 
 void AstPrinter::VisitGenericAstNode(AstNode* node) {
-  THR_Print("(%s ", node->PrettyName());
+  THR_Print("(%s ", node->Name());
   node->VisitChildren(this);
   THR_Print(")");
 }
@@ -30,7 +30,7 @@
 void AstPrinter::VisitSequenceNode(SequenceNode* node) {
   indent_++;
   LocalScope* scope = node->scope();
-  THR_Print("(%s (scope \"%p\"", node->PrettyName(), scope);
+  THR_Print("(%s (scope \"%p\"", node->Name(), scope);
   if (scope != NULL) {
     THR_Print(" (%s-%s) loop %d",
               scope->begin_token_pos().ToCString(),
@@ -83,7 +83,7 @@
       kind = "";
       UNREACHABLE();
   }
-  THR_Print("(%s %s", node->PrettyName(), kind);
+  THR_Print("(%s %s", node->Name(), kind);
   node->VisitChildren(this);
   THR_Print(")");
 }
@@ -92,7 +92,7 @@
 void AstPrinter::VisitGenericLocalNode(AstNode* node,
                                        const LocalVariable& var) {
   THR_Print("(%s %s%s \"%s\"",
-            node->PrettyName(),
+            node->Name(),
             var.is_final() ? "final " : "",
             String::Handle(var.type().Name()).ToCString(),
             var.name().ToCString());
@@ -121,7 +121,7 @@
 
 void AstPrinter::VisitGenericFieldNode(AstNode* node, const Field& field) {
   THR_Print("(%s %s%s \"%s\" ",
-            node->PrettyName(),
+            node->Name(),
             field.is_final() ? "final " : "",
             String::Handle(AbstractType::Handle(field.type()).Name()).
                 ToCString(),
@@ -137,7 +137,7 @@
 
 
 void AstPrinter::VisitStoreInstanceFieldNode(StoreInstanceFieldNode* node) {
-  VisitGenericFieldNode(node, node->field());
+  VisitGenericFieldNode(node, Field::ZoneHandle(node->field().Original()));
 }
 
 
@@ -168,14 +168,14 @@
 
 void AstPrinter::VisitLiteralNode(LiteralNode* node) {
   const Instance& literal = node->literal();
-  THR_Print("(%s \"%s\")", node->PrettyName(), literal.ToCString());
+  THR_Print("(%s \"%s\")", node->Name(), literal.ToCString());
 }
 
 
 void AstPrinter::VisitTypeNode(TypeNode* node) {
   const AbstractType& type = node->type();
   THR_Print("(%s \"%s\")",
-            node->PrettyName(),
+            node->Name(),
             String::Handle(type.Name()).ToCString());
 }
 
@@ -184,7 +184,7 @@
   const AbstractType& type = node->type();
   const String& dst_name = node->dst_name();
   THR_Print("(%s (type \"%s\") (of \"%s\") ",
-            node->PrettyName(),
+            node->Name(),
             String::Handle(type.Name()).ToCString(),
             dst_name.ToCString());
   node->VisitChildren(this);
@@ -193,7 +193,7 @@
 
 
 void AstPrinter::VisitAwaitNode(AwaitNode* node) {
-  THR_Print("(*****%s***** (scope \"%p\") ", node->PrettyName(), node->scope());
+  THR_Print("(*****%s***** (scope \"%p\") ", node->Name(), node->scope());
   node->VisitChildren(this);
   THR_Print(")");
 }
@@ -201,7 +201,7 @@
 
 void AstPrinter::VisitAwaitMarkerNode(AwaitMarkerNode* node) {
   THR_Print("(%s (async_scope \"%p\" await_scope \"%p\"))",
-            node->PrettyName(),
+            node->Name(),
             node->async_scope(),
             node->await_scope());
 }
@@ -209,27 +209,27 @@
 
 void AstPrinter::VisitPrimaryNode(PrimaryNode* node) {
   THR_Print("(*****%s***** \"%s\")",
-            node->PrettyName(),
+            node->Name(),
             node->primary().ToCString());
 }
 
 
 void AstPrinter::VisitComparisonNode(ComparisonNode* node) {
-  THR_Print("(%s %s ", node->PrettyName(), node->TokenName());
+  THR_Print("(%s %s ", node->Name(), node->TokenName());
   node->VisitChildren(this);
   THR_Print(")");
 }
 
 
 void AstPrinter::VisitBinaryOpNode(BinaryOpNode* node) {
-  THR_Print("(%s %s ", node->PrettyName(), node->TokenName());
+  THR_Print("(%s %s ", node->Name(), node->TokenName());
   node->VisitChildren(this);
   THR_Print(")");
 }
 
 
 void AstPrinter::VisitBinaryOpWithMask32Node(BinaryOpWithMask32Node* node) {
-  THR_Print("(%s %s ", node->PrettyName(), node->TokenName());
+  THR_Print("(%s %s ", node->Name(), node->TokenName());
   node->VisitChildren(this);
   THR_Print(" & \"0x%" Px64 "", node->mask32());
   THR_Print("\")");
@@ -237,7 +237,7 @@
 
 
 void AstPrinter::VisitUnaryOpNode(UnaryOpNode* node) {
-  THR_Print("(%s %s ", node->PrettyName(), node->TokenName());
+  THR_Print("(%s %s ", node->Name(), node->TokenName());
   node->VisitChildren(this);
   THR_Print(")");
 }
@@ -254,7 +254,7 @@
 
 
 void AstPrinter::VisitCaseNode(CaseNode* node) {
-  THR_Print("(%s (", node->PrettyName());
+  THR_Print("(%s (", node->Name());
   for (int i = 0; i < node->case_expressions()->length(); i++) {
     node->case_expressions()->NodeAt(i)->Visit(this);
   }
@@ -280,7 +280,7 @@
 void AstPrinter::VisitForNode(ForNode* node) {
   // Complicated because the condition is optional and so we clearly want to
   // indicate the subparts.
-  THR_Print("(%s (init ", node->PrettyName());
+  THR_Print("(%s (init ", node->Name());
   node->initializer()->Visit(this);
   if (node->condition() != NULL) {
     THR_Print(") (cond ");
@@ -301,7 +301,7 @@
 
 void AstPrinter::VisitJumpNode(JumpNode* node) {
   THR_Print("(%s %s %s (scope \"%p\"))",
-            node->PrettyName(),
+            node->Name(),
             node->TokenName(),
             node->label()->name().ToCString(),
             node->label()->owner());
@@ -310,7 +310,7 @@
 
 void AstPrinter::VisitInstanceCallNode(InstanceCallNode* node) {
   THR_Print("(%s \"%s\" ",
-            node->PrettyName(),
+            node->Name(),
             node->function_name().ToCString());
   node->VisitChildren(this);
   THR_Print(")");
@@ -319,7 +319,7 @@
 
 void AstPrinter::VisitStaticCallNode(StaticCallNode* node) {
   const char* function_fullname = node->function().ToFullyQualifiedCString();
-  THR_Print("(%s \"%s\" ", node->PrettyName(), function_fullname);
+  THR_Print("(%s \"%s\" ", node->Name(), function_fullname);
   node->VisitChildren(this);
   THR_Print(")");
 }
@@ -327,7 +327,7 @@
 
 void AstPrinter::VisitClosureNode(ClosureNode* node) {
   const char* function_fullname = node->function().ToFullyQualifiedCString();
-  THR_Print("(%s \"%s\")", node->PrettyName(), function_fullname);
+  THR_Print("(%s \"%s\")", node->Name(), function_fullname);
 }
 
 
@@ -339,32 +339,29 @@
 void AstPrinter::VisitConstructorCallNode(ConstructorCallNode* node) {
   const char* kind = node->constructor().IsFactory() ? "factory " : "";
   const char* constructor_name = node->constructor().ToFullyQualifiedCString();
-  THR_Print("(%s %s \"%s\" ", node->PrettyName(), kind, constructor_name);
+  THR_Print("(%s %s \"%s\" ", node->Name(), kind, constructor_name);
   node->VisitChildren(this);
   THR_Print(")");
 }
 
 
 void AstPrinter::VisitInstanceGetterNode(InstanceGetterNode* node) {
-  THR_Print("(%s \"%s\" ",
-            node->PrettyName(),
-            node->field_name().ToCString());
+  THR_Print("(%s \"%s\" ", node->Name(), node->field_name().ToCString());
   node->VisitChildren(this);
   THR_Print(")");
 }
 
 
 void AstPrinter::VisitInstanceSetterNode(InstanceSetterNode* node) {
-  THR_Print("(%s \"%s\" ",
-            node->PrettyName(),
-            node->field_name().ToCString());
+  THR_Print("(%s \"%s\" ", node->Name(), node->field_name().ToCString());
   node->VisitChildren(this);
   THR_Print(")");
 }
 
 
 void AstPrinter::VisitInitStaticFieldNode(InitStaticFieldNode* node) {
-  THR_Print("(%s \"%s\")", node->PrettyName(),
+  THR_Print("(%s \"%s\")",
+            node->Name(),
             String::Handle(node->field().name()).ToCString());
 }
 
@@ -372,7 +369,7 @@
 void AstPrinter::VisitStaticGetterNode(StaticGetterNode* node) {
   String& class_name = String::Handle(node->cls().Name());
   THR_Print("(%s \"%s.%s\")",
-            node->PrettyName(),
+            node->Name(),
             class_name.ToCString(),
             node->field_name().ToCString());
 }
@@ -381,7 +378,7 @@
 void AstPrinter::VisitStaticSetterNode(StaticSetterNode* node) {
   String& class_name = String::Handle(node->cls().Name());
   THR_Print("(%s \"%s.%s\" ",
-            node->PrettyName(),
+            node->Name(),
             class_name.ToCString(),
             node->field_name().ToCString());
   node->VisitChildren(this);
@@ -390,14 +387,14 @@
 
 
 void AstPrinter::VisitLoadIndexedNode(LoadIndexedNode* node) {
-  THR_Print("(%s%s ", node->PrettyName(), node->IsSuperLoad() ? " super" : "");
+  THR_Print("(%s%s ", node->Name(), node->IsSuperLoad() ? " super" : "");
   node->VisitChildren(this);
   THR_Print(")");
 }
 
 
 void AstPrinter::VisitStoreIndexedNode(StoreIndexedNode* node) {
-  THR_Print("(%s%s ", node->PrettyName(), node->IsSuperStore() ? " super" : "");
+  THR_Print("(%s%s ", node->Name(), node->IsSuperStore() ? " super" : "");
   node->VisitChildren(this);
   THR_Print(")");
 }
@@ -405,7 +402,7 @@
 
 void AstPrinter::VisitNativeBodyNode(NativeBodyNode* node) {
   THR_Print("(%s \"%s\" (%" Pd " args))",
-            node->PrettyName(),
+            node->Name(),
             node->native_c_function_name().ToCString(),
             NativeArguments::ParameterCountForResolution(node->function()));
 }
@@ -417,7 +414,7 @@
 
 
 void AstPrinter::VisitTryCatchNode(TryCatchNode* node) {
-  THR_Print("(%s ", node->PrettyName());
+  THR_Print("(%s ", node->Name());
   node->try_block()->Visit(this);
   node->catch_block()->Visit(this);
   if (node->finally_block() != NULL) {
@@ -435,7 +432,7 @@
 
 
 void AstPrinter::VisitStopNode(StopNode* node) {
-  THR_Print("(%s %s)", node->PrettyName(), node->message());
+  THR_Print("(%s %s)", node->Name(), node->message());
 }
 
 
diff --git a/runtime/vm/ast_transformer.cc b/runtime/vm/ast_transformer.cc
index 8b14e29..4b05867 100644
--- a/runtime/vm/ast_transformer.cc
+++ b/runtime/vm/ast_transformer.cc
@@ -521,9 +521,10 @@
 
 void AwaitTransformer::VisitStoreStaticFieldNode(StoreStaticFieldNode* node) {
   AstNode* new_value = Transform(node->value());
-  result_ = new(Z) StoreStaticFieldNode(node->token_pos(),
-                                        node->field(),
-                                        new_value);
+  result_ = new(Z) StoreStaticFieldNode(
+      node->token_pos(),
+      Field::ZoneHandle(Z, node->field().Original()),
+      new_value);
 }
 
 
diff --git a/runtime/vm/benchmark_test.cc b/runtime/vm/benchmark_test.cc
index 488a2d9..1c59f8d 100644
--- a/runtime/vm/benchmark_test.cc
+++ b/runtime/vm/benchmark_test.cc
@@ -20,8 +20,6 @@
 
 namespace dart {
 
-DECLARE_FLAG(bool, background_compilation);
-
 Benchmark* Benchmark::first_ = NULL;
 Benchmark* Benchmark::tail_ = NULL;
 const char* Benchmark::executable_ = NULL;
@@ -181,10 +179,15 @@
   stats->EnableBenchmark();
   Timer timer(true, "Compile all of dart2js benchmark");
   timer.Start();
+#if !defined(PRODUCT)
+  // Constant in product mode.
   const bool old_flag = FLAG_background_compilation;
   FLAG_background_compilation = false;
+#endif
   Dart_Handle result = Dart_CompileAll();
+#if !defined(PRODUCT)
   FLAG_background_compilation = old_flag;
+#endif
   EXPECT_VALID(result);
   timer.Stop();
   int64_t elapsed_time = timer.TotalElapsedTime();
@@ -387,10 +390,14 @@
   }
   Timer timer(true, "Compile all of dart2js benchmark");
   timer.Start();
+#if !defined(PRODUCT)
   const bool old_flag = FLAG_background_compilation;
   FLAG_background_compilation = false;
+#endif
   Dart_Handle result = Dart_CompileAll();
+#if !defined(PRODUCT)
   FLAG_background_compilation = old_flag;
+#endif
   EXPECT_VALID(result);
   timer.Stop();
   int64_t elapsed_time = timer.TotalElapsedTime();
diff --git a/runtime/vm/block_scheduler.cc b/runtime/vm/block_scheduler.cc
index 1288d0b..5b3d78d 100644
--- a/runtime/vm/block_scheduler.cc
+++ b/runtime/vm/block_scheduler.cc
@@ -11,8 +11,6 @@
 
 namespace dart {
 
-DEFINE_FLAG(bool, emit_edge_counters, true, "Emit edge counters at targets.");
-
 static intptr_t GetEdgeCount(const Array& edge_counters, intptr_t edge_id) {
   if (!FLAG_emit_edge_counters) {
     // Assume everything was visited once.
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 74304da..d1e9f5b 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -16,6 +16,7 @@
 namespace dart {
 
 DEFINE_FLAG(bool, print_classes, false, "Prints details about loaded classes.");
+DEFINE_FLAG(bool, reify, true, "Reify type arguments of generic types.");
 DEFINE_FLAG(bool, trace_class_finalization, false, "Trace class finalization.");
 DEFINE_FLAG(bool, trace_type_finalization, false, "Trace type finalization.");
 
@@ -389,7 +390,7 @@
     return;
   }
 
-  if (Isolate::Current()->flags().error_on_bad_override()) {
+  if (Isolate::Current()->error_on_bad_override()) {
     // Verify that the target is compatible with the redirecting factory.
     Error& error = Error::Handle();
     if (!target.HasCompatibleParametersWith(factory, &error)) {
@@ -670,6 +671,11 @@
   // The class has num_type_parameters type parameters.
   const intptr_t num_type_parameters = type_class.NumTypeParameters();
 
+  // If we are not reifying types, drop type arguments.
+  if (!FLAG_reify) {
+    type.set_arguments(TypeArguments::Handle(Z, TypeArguments::null()));
+  }
+
   // Initialize the type argument vector.
   // Check the number of parsed type arguments, if any.
   // Specifying no type arguments indicates a raw type, which is not an error.
@@ -677,7 +683,7 @@
   TypeArguments& arguments = TypeArguments::Handle(Z, type.arguments());
   if (!arguments.IsNull() && (arguments.Length() != num_type_parameters)) {
     // Wrong number of type arguments. The type is mapped to the raw type.
-    if (Isolate::Current()->flags().error_on_bad_type()) {
+    if (Isolate::Current()->error_on_bad_type()) {
       const String& type_class_name = String::Handle(Z, type_class.Name());
       ReportError(cls, type.token_pos(),
                   "wrong number of type arguments for class '%s'",
@@ -699,7 +705,7 @@
   // super types of type_class, which are initialized from the parsed
   // type arguments, followed by the parsed type arguments.
   TypeArguments& full_arguments = TypeArguments::Handle(Z);
-  if (num_type_arguments > 0) {
+  if (FLAG_reify && (num_type_arguments > 0)) {
     // If no type arguments were parsed and if the super types do not prepend
     // type arguments to the vector, we can leave the vector as null.
     if (!arguments.IsNull() || (num_type_arguments > num_type_parameters)) {
@@ -1456,7 +1462,7 @@
            !const_value.IsInstanceOf(type,
                                      Object::null_type_arguments(),
                                      &error))) {
-        if (Isolate::Current()->flags().error_on_bad_type()) {
+        if (Isolate::Current()->error_on_bad_type()) {
           const AbstractType& const_value_type = AbstractType::Handle(
               Z, const_value.GetType());
           const String& const_value_type_name = String::Handle(
@@ -1519,7 +1525,7 @@
     FinalizeSignature(cls, function);
     name = function.name();
     // Report signature conflicts only.
-    if (Isolate::Current()->flags().error_on_bad_override() &&
+    if (Isolate::Current()->error_on_bad_override() &&
         !function.is_static() && !function.IsGenerativeConstructor()) {
       // A constructor cannot override anything.
       for (intptr_t i = 0; i < interfaces.length(); i++) {
@@ -2259,7 +2265,7 @@
                 script, func.token_pos(), Report::AtLocation,
                 Report::kError, Heap::kNew,
                 "constructor '%s' is illegal in mixin class %s",
-                String::Handle(func.PrettyName()).ToCString(),
+                String::Handle(func.UserVisibleName()).ToCString(),
                 String::Handle(zone, mixin_cls.Name()).ToCString()));
 
         ReportErrors(error, cls, cls.token_pos(),
@@ -2710,7 +2716,7 @@
       }
       return;
     }
-    if (Isolate::Current()->flags().error_on_bad_type()) {
+    if (Isolate::Current()->error_on_bad_type()) {
       const String& type_class_name = String::Handle(type_class.Name());
       ReportError(cls, type.token_pos(),
                   "wrong number of type arguments for class '%s'",
@@ -3142,7 +3148,7 @@
           prev_error, script, type.token_pos(), Report::AtLocation,
           Report::kMalformedType, Heap::kOld,
           format, args));
-  if (Isolate::Current()->flags().error_on_bad_type()) {
+  if (Isolate::Current()->error_on_bad_type()) {
     ReportError(error);
   }
   type.set_error(error);
@@ -3204,7 +3210,7 @@
           Report::kMalboundedType, Heap::kOld,
           format, args));
   va_end(args);
-  if (Isolate::Current()->flags().error_on_bad_type()) {
+  if (Isolate::Current()->error_on_bad_type()) {
     ReportError(error);
   }
   type.set_error(error);
diff --git a/runtime/vm/code_descriptors.cc b/runtime/vm/code_descriptors.cc
index a286a04..dad76d9 100644
--- a/runtime/vm/code_descriptors.cc
+++ b/runtime/vm/code_descriptors.cc
@@ -6,8 +6,6 @@
 
 namespace dart {
 
-DECLARE_FLAG(bool, precompilation);
-
 void DescriptorList::AddDescriptor(RawPcDescriptors::Kind kind,
                                    intptr_t pc_offset,
                                    intptr_t deopt_id,
@@ -18,7 +16,7 @@
          (deopt_id != Thread::kNoDeoptId));
 
   // When precompiling, we only use pc descriptors for exceptions.
-  if (!FLAG_precompilation || try_index != -1) {
+  if (!FLAG_precompiled_mode || try_index != -1) {
     intptr_t merged_kind_try =
         RawPcDescriptors::MergedKindTry::Encode(kind, try_index);
 
@@ -46,6 +44,9 @@
 
 void CodeSourceMapBuilder::AddEntry(intptr_t pc_offset,
                                     TokenPosition token_pos) {
+  // Require pc offset to monotonically increase.
+  ASSERT((prev_pc_offset < pc_offset) ||
+         ((prev_pc_offset == 0) && (pc_offset == 0)));
   CodeSourceMap::EncodeInteger(&encoded_data_, pc_offset - prev_pc_offset);
   CodeSourceMap::EncodeInteger(&encoded_data_,
                                token_pos.value() - prev_token_pos);
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index 4e23a6d..758c2e0 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -27,22 +27,11 @@
 
 namespace dart {
 
-DEFINE_FLAG(bool, deoptimize_alot, false,
-    "Deoptimizes all live frames when we are about to return to Dart code from"
-    " native entries.");
-DEFINE_FLAG(bool, background_compilation, false,
-    "Run optimizing compilation in background");
 DEFINE_FLAG(int, max_subtype_cache_entries, 100,
     "Maximum number of subtype cache entries (number of checks cached).");
-DEFINE_FLAG(int, optimization_counter_threshold, 30000,
-    "Function's usage-counter value before it is optimized, -1 means never");
 DEFINE_FLAG(int, regexp_optimization_counter_threshold, 1000,
     "RegExp's usage-counter value before it is optimized, -1 means never");
 DEFINE_FLAG(charp, optimization_filter, NULL, "Optimize only named function");
-// TODO(srdjan): Remove this flag once background compilation of regular
-// expressions is possible.
-DEFINE_FLAG(bool, regexp_opt_in_background, false,
-    "Optimize reg-exp functions in background");
 DEFINE_FLAG(int, reoptimization_counter_threshold, 4000,
     "Counter threshold before a function gets reoptimized.");
 DEFINE_FLAG(bool, stop_on_excessive_deoptimization, false,
@@ -66,17 +55,13 @@
 DECLARE_FLAG(bool, trace_compiler);
 DECLARE_FLAG(bool, trace_optimizing_compiler);
 DECLARE_FLAG(int, max_polymorphic_checks);
-DECLARE_FLAG(bool, precompilation);
 
-DEFINE_FLAG(bool, use_osr, true, "Use on-stack replacement.");
 DEFINE_FLAG(bool, trace_osr, false, "Trace attempts at on-stack replacement.");
 
 DEFINE_FLAG(int, stacktrace_every, 0,
             "Compute debugger stacktrace on every N stack overflow checks");
 DEFINE_FLAG(charp, stacktrace_filter, NULL,
             "Compute stacktrace in named function on stack overflow checks");
-DEFINE_FLAG(int, deoptimize_every, 0,
-            "Deoptimize on every N stack overflow checks");
 DEFINE_FLAG(charp, deoptimize_filter, NULL,
             "Deoptimize in named function on stack overflow checks");
 
@@ -243,7 +228,7 @@
   // Code inlined in the caller should have optimized the case where the
   // instantiator can be reused as type argument vector.
   ASSERT(instantiator.IsNull() || !type_arguments.IsUninstantiatedIdentity());
-  if (isolate->flags().type_checks()) {
+  if (isolate->type_checks()) {
     Error& bound_error = Error::Handle();
     type_arguments =
         type_arguments.InstantiateAndCanonicalizeFrom(instantiator,
@@ -505,8 +490,7 @@
 // Return value: instance if a subtype, otherwise throw a TypeError.
 DEFINE_RUNTIME_ENTRY(TypeCheck, 5) {
   const Instance& src_instance = Instance::CheckedHandle(arguments.ArgAt(0));
-  const AbstractType& dst_type =
-      AbstractType::CheckedHandle(arguments.ArgAt(1));
+  AbstractType& dst_type = AbstractType::CheckedHandle(arguments.ArgAt(1));
   const TypeArguments& instantiator_type_arguments =
       TypeArguments::CheckedHandle(arguments.ArgAt(2));
   const String& dst_name = String::CheckedHandle(arguments.ArgAt(3));
@@ -531,40 +515,21 @@
     const TokenPosition location = GetCallerLocation();
     const AbstractType& src_type = AbstractType::Handle(src_instance.GetType());
     String& src_type_name = String::Handle(src_type.UserVisibleName());
-    String& dst_type_name = String::Handle();
-    Library& dst_type_lib = Library::Handle();
     if (!dst_type.IsInstantiated()) {
       // Instantiate dst_type before reporting the error.
-      const AbstractType& instantiated_dst_type = AbstractType::Handle(
-          dst_type.InstantiateFrom(instantiator_type_arguments, NULL,
-                                   NULL, NULL, Heap::kNew));
-      // Note that instantiated_dst_type may be malbounded.
-      dst_type_name = instantiated_dst_type.UserVisibleName();
-      dst_type_lib =
-          Class::Handle(instantiated_dst_type.type_class()).library();
-    } else {
-      dst_type_name = dst_type.UserVisibleName();
-      dst_type_lib = Class::Handle(dst_type.type_class()).library();
+      dst_type = dst_type.InstantiateFrom(instantiator_type_arguments, NULL,
+                                          NULL, NULL, Heap::kNew);
+      // Note that instantiated dst_type may be malbounded.
     }
+    String& dst_type_name = String::Handle(dst_type.UserVisibleName());
     String& bound_error_message =  String::Handle();
     if (!bound_error.IsNull()) {
-      ASSERT(isolate->flags().type_checks());
+      ASSERT(isolate->type_checks());
       bound_error_message = String::New(bound_error.ToErrorCString());
     }
     if (src_type_name.Equals(dst_type_name)) {
-      // Qualify the names with their libraries.
-      String& lib_name = String::Handle();
-      lib_name = Library::Handle(
-          Class::Handle(src_type.type_class()).library()).name();
-      if (lib_name.Length() != 0) {
-        lib_name = String::Concat(lib_name, Symbols::Dot());
-        src_type_name = String::Concat(lib_name, src_type_name);
-      }
-      lib_name = dst_type_lib.name();
-      if (lib_name.Length() != 0) {
-        lib_name = String::Concat(lib_name, Symbols::Dot());
-        dst_type_name = String::Concat(lib_name, dst_type_name);
-      }
+      src_type_name = src_type.UserVisibleNameWithURI();
+      dst_type_name = dst_type.UserVisibleNameWithURI();
     }
     Exceptions::CreateAndThrowTypeError(location, src_type_name, dst_type_name,
                                         dst_name, bound_error_message);
@@ -1384,7 +1349,7 @@
       ActivationFrame* frame = stack->FrameAt(i);
       // Variable locations and number are unknown when precompiling.
       const int num_vars =
-         FLAG_precompilation ? 0 : frame->NumLocalVariables();
+         FLAG_precompiled_mode ? 0 : frame->NumLocalVariables();
       TokenPosition unused = TokenPosition::kNoSource;
       for (intptr_t v = 0; v < num_vars; v++) {
         frame->VariableAt(v, &var_name, &unused, &unused, &var_value);
@@ -1476,6 +1441,7 @@
 // The requesting function can be already optimized (reoptimization).
 // Returns the Code object where to continue execution.
 DEFINE_RUNTIME_ENTRY(OptimizeInvokedFunction, 1) {
+#if !defined(DART_PRECOMPILED_RUNTIME)
   const Function& function = Function::CheckedHandle(zone,
                                                      arguments.ArgAt(0));
   ASSERT(!function.IsNull());
@@ -1495,8 +1461,7 @@
       }
     }
     // TODO(srdjan): Fix background compilation of regular expressions.
-    if (FLAG_background_compilation &&
-        (!function.IsIrregexpFunction() || FLAG_regexp_opt_in_background)) {
+    if (FLAG_background_compilation) {
       if (FLAG_enable_inlining_annotations) {
         FATAL("Cannot enable inlining annotations and background compilation");
       }
@@ -1531,6 +1496,9 @@
     ASSERT(!optimized_code.IsNull());
   }
   arguments.SetReturn(Code::Handle(zone, function.CurrentCode()));
+#else
+  UNREACHABLE();
+#endif  // !DART_PRECOMPILED_RUNTIME
 }
 
 
@@ -1554,9 +1522,6 @@
   ASSERT(caller_code.is_optimized());
   const Function& target_function = Function::Handle(
       zone, caller_code.GetStaticCallTargetFunctionAt(frame->pc()));
-  const Code& target_code = Code::Handle(
-      zone, caller_code.GetStaticCallTargetCodeAt(frame->pc()));
-  ASSERT(!target_code.IsNull());
   if (!target_function.HasCode()) {
     const Error& error = Error::Handle(
         zone, Compiler::CompileFunction(thread, target_function));
@@ -1565,7 +1530,6 @@
     }
   }
   ASSERT(target_function.HasCode());
-  ASSERT(target_function.raw() == target_code.function());
 
   const Code& current_target_code = Code::Handle(
       zone, target_function.CurrentCode());
@@ -1575,11 +1539,10 @@
   caller_code.SetStaticCallTargetCodeAt(frame->pc(), current_target_code);
   if (FLAG_trace_patching) {
     OS::PrintErr("FixCallersTarget: caller %#" Px " "
-        "target '%s' %#" Px " -> %#" Px "\n",
-        frame->pc(),
-        target_function.ToFullyQualifiedCString(),
-        target_code.EntryPoint(),
-        current_target_code.EntryPoint());
+                 "target '%s' -> %#" Px "\n",
+                 frame->pc(),
+                 target_function.ToFullyQualifiedCString(),
+                 current_target_code.EntryPoint());
   }
   arguments.SetReturn(current_target_code);
 }
@@ -1588,6 +1551,7 @@
 // The caller tried to allocate an instance via an invalidated allocation
 // stub.
 DEFINE_RUNTIME_ENTRY(FixAllocationStubTarget, 0) {
+#if !defined(DART_PRECOMPILED_RUNTIME)
   StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames);
   StackFrame* frame = iterator.NextFrame();
   ASSERT(frame != NULL);
@@ -1623,6 +1587,9 @@
         alloc_stub.EntryPoint());
   }
   arguments.SetReturn(alloc_stub);
+#else
+  UNREACHABLE();
+#endif
 }
 
 
@@ -1695,7 +1662,7 @@
   }
 }
 
-
+#if !defined(DART_PRECOMPILED_RUNTIME)
 static void CopySavedRegisters(uword saved_registers_address,
                                fpu_register_t** fpu_registers,
                                intptr_t** cpu_registers) {
@@ -1720,6 +1687,7 @@
   }
   *cpu_registers = cpu_registers_copy;
 }
+#endif
 
 
 // Copies saved registers and caller's frame into temporary buffers.
@@ -1731,6 +1699,7 @@
                           2,
                           uword saved_registers_address,
                           uword is_lazy_deopt) {
+#if !defined(DART_PRECOMPILED_RUNTIME)
   Thread* thread = Thread::Current();
   Isolate* isolate = thread->isolate();
   StackZone zone(thread);
@@ -1777,6 +1746,10 @@
 
   // Stack size (FP - SP) in bytes.
   return deopt_context->DestStackAdjustment() * kWordSize;
+#else
+  UNREACHABLE();
+  return 0;
+#endif  // !DART_PRECOMPILED_RUNTIME
 }
 END_LEAF_RUNTIME_ENTRY
 
@@ -1784,6 +1757,7 @@
 // The stack has been adjusted to fit all values for unoptimized frame.
 // Fill the unoptimized frame.
 DEFINE_LEAF_RUNTIME_ENTRY(void, DeoptimizeFillFrame, 1, uword last_fp) {
+#if !defined(DART_PRECOMPILED_RUNTIME)
   Thread* thread = Thread::Current();
   Isolate* isolate = thread->isolate();
   StackZone zone(thread);
@@ -1818,6 +1792,9 @@
       caller_frame->sp() - (kDartFrameFixedSize * kWordSize));
   deopt_context->set_dest_frame(start);
   deopt_context->FillDestFrame();
+#else
+  UNREACHABLE();
+#endif  // !DART_PRECOMPILED_RUNTIME
 }
 END_LEAF_RUNTIME_ENTRY
 
@@ -1828,6 +1805,7 @@
 // under return address to keep them discoverable by GC that can occur during
 // materialization phase.
 DEFINE_RUNTIME_ENTRY(DeoptimizeMaterialize, 0) {
+#if !defined(DART_PRECOMPILED_RUNTIME)
   DeoptContext* deopt_context = isolate->deopt_context();
   intptr_t deopt_arg_count = deopt_context->MaterializeDeferredObjects();
   isolate->set_deopt_context(NULL);
@@ -1836,6 +1814,9 @@
   // Return value tells deoptimization stub to remove the given number of bytes
   // from the stack.
   arguments.SetReturn(Smi::Handle(Smi::New(deopt_arg_count * kWordSize)));
+#else
+  UNREACHABLE();
+#endif  // !DART_PRECOMPILED_RUNTIME
 }
 
 
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index 39c8846..dd2ddee 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -24,10 +24,10 @@
 #include "vm/flow_graph_builder.h"
 #include "vm/flow_graph_compiler.h"
 #include "vm/flow_graph_inliner.h"
-#include "vm/flow_graph_optimizer.h"
 #include "vm/flow_graph_range_analysis.h"
 #include "vm/flow_graph_type_propagator.h"
 #include "vm/il_printer.h"
+#include "vm/jit_optimizer.h"
 #include "vm/longjump.h"
 #include "vm/object.h"
 #include "vm/object_store.h"
@@ -59,6 +59,7 @@
     "Print the IR flow graph when optimizing.");
 DEFINE_FLAG(bool, print_ic_data_map, false,
     "Print the deopt-id to ICData map in optimizing compiler.");
+DEFINE_FLAG(bool, print_code_source_map, false, "Print code source map.");
 DEFINE_FLAG(bool, range_analysis, true, "Enable range analysis");
 DEFINE_FLAG(bool, reorder_basic_blocks, true, "Enable basic-block reordering.");
 DEFINE_FLAG(bool, trace_compiler, false, "Trace compiler operations.");
@@ -69,12 +70,9 @@
 DEFINE_FLAG(bool, verify_compiler, false,
     "Enable compiler verification assertions");
 
-DECLARE_FLAG(bool, background_compilation);
 DECLARE_FLAG(bool, huge_method_cutoff_in_code_size);
-DECLARE_FLAG(bool, load_deferred_eagerly);
 DECLARE_FLAG(bool, trace_failed_optimization_attempts);
 DECLARE_FLAG(bool, trace_irregexp);
-DECLARE_FLAG(bool, precompilation);
 
 
 #ifndef DART_PRECOMPILED_RUNTIME
@@ -420,7 +418,7 @@
     Assembler* assembler,
     FlowGraphCompiler* graph_compiler,
     FlowGraph* flow_graph) {
-  ASSERT(!FLAG_precompilation);
+  ASSERT(!FLAG_precompiled_mode);
   const Function& function = parsed_function()->function();
   Zone* const zone = thread()->zone();
 
@@ -460,6 +458,12 @@
            caller_inlining_id_map_array.Length() * sizeof(uword));
   code.SetInlinedCallerIdMap(caller_inlining_id_map_array);
 
+  const Array& inlined_id_to_token_pos =
+      Array::Handle(zone, graph_compiler->InliningIdToTokenPos());
+  INC_STAT(thread(), total_code_size,
+           inlined_id_to_token_pos.Length() * sizeof(uword));
+  code.SetInlinedIdToTokenPos(inlined_id_to_token_pos);
+
   graph_compiler->FinalizePcDescriptors(code);
   code.set_deopt_info_array(deopt_info_array);
 
@@ -468,6 +472,18 @@
   graph_compiler->FinalizeExceptionHandlers(code);
   graph_compiler->FinalizeStaticCallTargetsTable(code);
 
+NOT_IN_PRODUCT(
+  // Set the code source map after setting the inlined information because
+  // we use the inlined information when printing.
+  const CodeSourceMap& code_source_map =
+      CodeSourceMap::Handle(
+          zone,
+          graph_compiler->code_source_map_builder()->Finalize());
+  code.set_code_source_map(code_source_map);
+  if (FLAG_print_code_source_map) {
+    CodeSourceMap::Dump(code_source_map, code, function);
+  }
+);
   if (optimized()) {
     // Installs code while at safepoint.
     if (thread()->IsMutatorThread()) {
@@ -556,7 +572,7 @@
 // If optimized_result_code is not NULL then it is caller's responsibility
 // to install code.
 bool CompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) {
-  ASSERT(!FLAG_precompilation);
+  ASSERT(!FLAG_precompiled_mode);
   const Function& function = parsed_function()->function();
   if (optimized() && !function.IsOptimizable()) {
     return false;
@@ -673,6 +689,8 @@
       // Maps inline_id_to_function[inline_id] -> function. Top scope
       // function has inline_id 0. The map is populated by the inliner.
       GrowableArray<const Function*> inline_id_to_function;
+      // Token position where inlining occured.
+      GrowableArray<TokenPosition> inline_id_to_token_pos;
       // For a given inlining-id(index) specifies the caller's inlining-id.
       GrowableArray<intptr_t> caller_inline_id;
       // Collect all instance fields that are loaded in the graph and
@@ -683,13 +701,13 @@
                                                  compiler_timeline,
                                                  "OptimizationPasses"));
         inline_id_to_function.Add(&function);
+        inline_id_to_token_pos.Add(function.token_pos());
         // Top scope function has no caller (-1).
         caller_inline_id.Add(-1);
         CSTAT_TIMER_SCOPE(thread(), graphoptimizer_timer);
 
-        FlowGraphOptimizer optimizer(flow_graph,
-                                     use_speculative_inlining,
-                                     NULL);
+        JitOptimizer optimizer(flow_graph);
+
         optimizer.ApplyICData();
         DEBUG_ASSERT(flow_graph->VerifyUseLists());
 
@@ -716,6 +734,7 @@
 
           FlowGraphInliner inliner(flow_graph,
                                    &inline_id_to_function,
+                                   &inline_id_to_token_pos,
                                    &caller_inline_id,
                                    use_speculative_inlining,
                                    NULL);
@@ -986,6 +1005,7 @@
       FlowGraphCompiler graph_compiler(&assembler, flow_graph,
                                        *parsed_function(), optimized(),
                                        inline_id_to_function,
+                                       inline_id_to_token_pos,
                                        caller_inline_id);
       {
         CSTAT_TIMER_SCOPE(thread(), graphcompiler_timer);
@@ -1087,7 +1107,7 @@
                                        const Function& function,
                                        bool optimized,
                                        intptr_t osr_id) {
-  ASSERT(!FLAG_precompilation);
+  ASSERT(!FLAG_precompiled_mode);
   LongJumpScope jump;
   if (setjmp(*jump.Set()) == 0) {
     Thread* const thread = Thread::Current();
@@ -1201,7 +1221,7 @@
 RawError* Compiler::CompileFunction(Thread* thread,
                                     const Function& function) {
 #ifdef DART_PRECOMPILER
-  if (FLAG_precompilation) {
+  if (FLAG_precompiled_mode) {
     return Precompiler::CompileFunction(thread, function);
   }
 #endif
@@ -1268,11 +1288,8 @@
 
   // Optimization must happen in non-mutator/Dart thread if background
   // compilation is on. OSR compilation still occurs in the main thread.
-  // TODO(Srdjan): Remove assert allowance for regular expression functions
-  // once they can be compiled in background.
   ASSERT((osr_id != kNoOSRDeoptId) || !FLAG_background_compilation ||
-         !thread->IsMutatorThread() ||
-         function.IsIrregexpFunction());
+         !thread->IsMutatorThread());
   CompilationPipeline* pipeline =
       CompilationPipeline::New(thread->zone(), function);
   return CompileFunctionHelper(pipeline,
@@ -1361,7 +1378,7 @@
 
 RawObject* Compiler::EvaluateStaticInitializer(const Field& field) {
 #ifdef DART_PRECOMPILER
-  if (FLAG_precompilation) {
+  if (FLAG_precompiled_mode) {
     return Precompiler::EvaluateStaticInitializer(field);
   }
 #endif
@@ -1405,7 +1422,7 @@
 
 RawObject* Compiler::ExecuteOnce(SequenceNode* fragment) {
 #ifdef DART_PRECOMPILER
-  if (FLAG_precompilation) {
+  if (FLAG_precompiled_mode) {
     return Precompiler::ExecuteOnce(fragment);
   }
 #endif
diff --git a/runtime/vm/compiler_test.cc b/runtime/vm/compiler_test.cc
index f1b916c..8dd7c2f 100644
--- a/runtime/vm/compiler_test.cc
+++ b/runtime/vm/compiler_test.cc
@@ -15,8 +15,6 @@
 
 namespace dart {
 
-DECLARE_FLAG(bool, background_compilation);
-
 VM_TEST_CASE(CompileScript) {
   const char* kScriptChars =
       "class A {\n"
@@ -98,7 +96,10 @@
   CompilerTest::TestCompileFunction(func);
   EXPECT(func.HasCode());
   EXPECT(!func.HasOptimizedCode());
+#if !defined(PRODUCT)
+  // Constant in product mode.
   FLAG_background_compilation = true;
+#endif
   BackgroundCompiler::EnsureInit(thread);
   Isolate* isolate = thread->isolate();
   ASSERT(isolate->background_compiler() != NULL);
@@ -122,7 +123,6 @@
             "  return unOpt();\n"
             "}\n";
 
-  // Isolate::Current()->flags().set_checked(true);
   Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
   Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
   EXPECT_VALID(result);
diff --git a/runtime/vm/constant_propagator.cc b/runtime/vm/constant_propagator.cc
index 695c23c..fa21b0f 100644
--- a/runtime/vm/constant_propagator.cc
+++ b/runtime/vm/constant_propagator.cc
@@ -19,8 +19,6 @@
 DEFINE_FLAG(bool, trace_constant_propagation, false,
     "Print constant propagation and useless code elimination.");
 
-DECLARE_FLAG(bool, fields_may_be_reset);
-
 // Quick access to the current zone and isolate.
 #define I (isolate())
 #define Z (graph_->zone())
diff --git a/runtime/vm/constants_arm64.h b/runtime/vm/constants_arm64.h
index 913a69c..7a0a18b 100644
--- a/runtime/vm/constants_arm64.h
+++ b/runtime/vm/constants_arm64.h
@@ -330,6 +330,8 @@
   SystemMask = 0xffc00000,
   SystemFixed = CompareBranchFixed | B31 | B30 | B24,
   HINT = SystemFixed | B17 | B16 | B13 | B4 | B3 | B2 | B1 | B0,
+  CLREX = SystemFixed | B17 | B16 | B13 | B12 | B11 | B10 | B9 | B8 |
+      B6 | B4 | B3 | B2 | B1 | B0,
 };
 
 // C3.2.5
@@ -364,6 +366,14 @@
   LDRpc = LoadRegLiteralFixed,
 };
 
+// C3.3.6
+enum LoadStoreExclusiveOp {
+  LoadStoreExclusiveMask = 0x3f000000,
+  LoadStoreExclusiveFixed = B27,
+  LDXR = LoadStoreExclusiveFixed | B22,
+  STXR = LoadStoreExclusiveFixed,
+};
+
 // C3.3.7-10
 enum LoadStoreRegOp {
   LoadStoreRegMask = 0x3a000000,
@@ -616,6 +626,7 @@
 _V(LoadStoreReg)                                                               \
 _V(LoadStoreRegPair)                                                           \
 _V(LoadRegLiteral)                                                             \
+_V(LoadStoreExclusive)                                                         \
 _V(AddSubImm)                                                                  \
 _V(LogicalImm)                                                                 \
 _V(MoveWide)                                                                   \
@@ -692,6 +703,8 @@
   kRtBits = 5,
   kRt2Shift = 10,
   kRt2Bits = 5,
+  kRsShift = 16,
+  kRsBits = 5,
 
   // V Registers.
   kVdShift = 0,
@@ -892,6 +905,8 @@
                                         Bits(kRtShift, kRtBits)); }
   inline Register Rt2Field() const { return static_cast<Register>(
                                         Bits(kRt2Shift, kRt2Bits)); }
+  inline Register RsField() const { return static_cast<Register>(
+                                        Bits(kRsShift, kRsBits)); }
 
   inline VRegister VdField() const { return static_cast<VRegister>(
                                         Bits(kVdShift, kVdBits)); }
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index 895d6b1..bef0ebb 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -131,9 +131,8 @@
     const bool precompiled = instructions_snapshot != NULL;
 
     // Setup default flags for the VM isolate.
-    Isolate::Flags vm_flags;
     Dart_IsolateFlags api_flags;
-    vm_flags.CopyTo(&api_flags);
+    Isolate::FlagsInitialize(&api_flags);
     vm_isolate_ = Isolate::Init("vm-isolate", api_flags, is_vm_isolate);
     start_time_ = vm_isolate_->start_time();
     vm_isolate_->set_compilation_allowed(!precompiled);
@@ -454,11 +453,14 @@
     StubCode::Init(I);
   }
 
+#if !defined(DART_PRECOMPILED_RUNTIME)
   // When running precompiled, the megamorphic miss function/code comes from the
   // snapshot.
   if (!Dart::IsRunningPrecompiledCode()) {
     MegamorphicCacheTable::InitMissHandler(I);
   }
+#endif
+
   const Code& miss_code =
       Code::Handle(I->object_store()->megamorphic_miss_code());
   I->set_ic_miss_code(miss_code);
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 4c27091..4c6fd00 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -51,8 +51,6 @@
 #define Z (T->zone())
 
 
-DECLARE_FLAG(bool, load_deferred_eagerly);
-DECLARE_FLAG(bool, precompilation);
 DECLARE_FLAG(bool, print_class_table);
 DECLARE_FLAG(bool, verify_handles);
 #if defined(DART_NO_SNAPSHOT)
@@ -1147,7 +1145,7 @@
     Dart_FileCloseCallback file_close,
     Dart_EntropySource entropy_source,
     Dart_GetVMServiceAssetsArchive get_service_assets) {
-  if ((instructions_snapshot != NULL) && !FLAG_precompilation) {
+  if ((instructions_snapshot != NULL) && !FLAG_precompiled_mode) {
     return strdup("Flag --precompilation was not specified.");
   }
   if (interrupt != NULL) {
@@ -1242,8 +1240,7 @@
   // Setup default flags in case none were passed.
   Dart_IsolateFlags api_flags;
   if (flags == NULL) {
-    Isolate::Flags vm_flags;
-    vm_flags.CopyTo(&api_flags);
+    Isolate::FlagsInitialize(&api_flags);
     flags = &api_flags;
   }
   Isolate* I = Dart::CreateIsolate(isolate_name, *flags);
@@ -1613,12 +1610,12 @@
   CHECK_API_SCOPE(T);
   CHECK_CALLBACK_STATE(T);
   API_TIMELINE_BEGIN_END;
-  Monitor monitor;
-  MonitorLocker ml(&monitor);
+  // The message handler run loop does not expect to have a current isolate
+  // so we exit the isolate here and enter it again after the runloop is done.
+  ::Dart_ExitIsolate();
   {
-    // The message handler run loop does not expect to have a current isolate
-    // so we exit the isolate here and enter it again after the runloop is done.
-    Dart_ExitIsolate();
+    Monitor monitor;
+    MonitorLocker ml(&monitor);
     RunLoopData data;
     data.monitor = &monitor;
     data.done = false;
@@ -1628,8 +1625,8 @@
     while (!data.done) {
       ml.Wait();
     }
-    ::Dart_EnterIsolate(Api::CastIsolate(I));
   }
+  ::Dart_EnterIsolate(Api::CastIsolate(I));
   if (T->sticky_error() != Object::null()) {
     Dart_Handle error = Api::NewHandle(T, T->sticky_error());
     T->clear_sticky_error();
@@ -4321,7 +4318,7 @@
       getter = lib.LookupFunctionAllowPrivate(getter_name);
     } else if (!field.IsNull() && field.IsUninitialized()) {
       // A field was found.  Check for a getter in the field's owner classs.
-      const Class& cls = Class::Handle(Z, field.owner());
+      const Class& cls = Class::Handle(Z, field.Owner());
       const String& getter_name = String::Handle(Z,
           Field::GetterName(field_name));
       getter = cls.LookupStaticFunctionAllowPrivate(getter_name);
@@ -4967,6 +4964,44 @@
 
 
 // --- Environment ---
+RawString* Api::GetEnvironmentValue(Thread* thread, const String& name) {
+  String& result = String::Handle(CallEnvironmentCallback(thread, name));
+  if (result.IsNull()) {
+    // Every 'dart:X' library introduces an environment variable
+    // 'dart.library.X' that is set to 'true'.
+    // We just need to make sure to hide private libraries (starting with
+    // "_", and the mirrors library, if it is not supported.
+
+    if (!FLAG_enable_mirrors && name.Equals(Symbols::DartLibraryMirrors())) {
+      return Symbols::False().raw();
+    }
+
+    const String& prefix = Symbols::DartLibrary();
+    if (name.StartsWith(prefix)) {
+      const String& library_name =
+          String::Handle(String::SubString(name, prefix.Length()));
+
+      // Private libraries (starting with "_") are not exposed to the user.
+      if (!library_name.IsNull() && library_name.CharAt(0) != '_') {
+        const String& dart_library_name =
+            String::Handle(String::Concat(Symbols::DartScheme(), library_name));
+        const Library& library =
+            Library::Handle(Library::LookupLibrary(dart_library_name));
+        if (!library.IsNull()) {
+          return Symbols::True().raw();
+        }
+      }
+    }
+    // Check for default VM provided values. If it was not overriden on the
+    // command line.
+    if (Symbols::DartIsVM().Equals(name)) {
+      return Symbols::True().raw();
+    }
+  }
+  return result.raw();
+}
+
+
 RawString* Api::CallEnvironmentCallback(Thread* thread, const String& name) {
   Isolate* isolate = thread->isolate();
   Dart_EnvironmentCallback callback = isolate->environment_callback();
@@ -4988,15 +5023,6 @@
           String::Handle(String::New("Illegal environment value")));
     }
   }
-  if (result.IsNull()) {
-    // TODO(iposva): Determine whether builtin values can be overriden by the
-    // embedder.
-    // Check for default VM provided values. If it was not overriden on the
-    // command line.
-    if (Symbols::DartIsVM().Equals(name)) {
-      return Symbols::True().raw();
-    }
-  }
   return result.raw();
 }
 
@@ -6100,7 +6126,7 @@
     bool reset_fields) {
   API_TIMELINE_BEGIN_END;
   DARTSCOPE(Thread::Current());
-  if (!FLAG_precompilation) {
+  if (!FLAG_precompiled_mode) {
     return Dart_NewApiError("Flag --precompilation was not specified.");
   }
   Dart_Handle result = Api::CheckAndFinalizePendingClasses(T);
diff --git a/runtime/vm/dart_api_impl.h b/runtime/vm/dart_api_impl.h
index 9820417..67c0257 100644
--- a/runtime/vm/dart_api_impl.h
+++ b/runtime/vm/dart_api_impl.h
@@ -260,12 +260,13 @@
   static void SetWeakHandleReturnValue(NativeArguments* args,
                                        Dart_WeakPersistentHandle retval);
 
-  static RawString* CallEnvironmentCallback(Thread* thread,
-                                            const String& name);
+  static RawString* GetEnvironmentValue(Thread* thread, const String& name);
 
  private:
   static Dart_Handle InitNewHandle(Thread* thread, RawObject* raw);
 
+  static RawString* CallEnvironmentCallback(Thread* thread, const String& name);
+
   // Thread local key used by the API. Currently holds the current
   // ApiNativeScope if any.
   static ThreadLocalKey api_native_key_;
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index 8e7d698..91043ed 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -19,7 +19,6 @@
 
 namespace dart {
 
-DECLARE_FLAG(int, optimization_counter_threshold);
 DECLARE_FLAG(bool, verify_acquired_data);
 DECLARE_FLAG(bool, ignore_patch_signature_mismatch);
 
@@ -1906,6 +1905,9 @@
 }
 
 
+#ifndef PRODUCT
+
+
 static const intptr_t kOptExtLength = 16;
 static int8_t opt_data[kOptExtLength] = { 0x01, 0x02, 0x03, 0x04,
                                           0x05, 0x06, 0x07, 0x08,
@@ -1974,6 +1976,9 @@
 }
 
 
+#endif  // !PRODUCT
+
+
 static void TestTypedDataDirectAccess() {
   Dart_Handle str = Dart_NewStringFromCString("junk");
   Dart_Handle byte_array = Dart_NewTypedData(Dart_TypedData_kUint8, 10);
diff --git a/runtime/vm/dart_api_state.h b/runtime/vm/dart_api_state.h
index 3c7d316..b510377 100644
--- a/runtime/vm/dart_api_state.h
+++ b/runtime/vm/dart_api_state.h
@@ -213,6 +213,10 @@
     return reinterpret_cast<Dart_WeakPersistentHandle>(this);
   }
 
+  intptr_t external_size() const {
+    return ExternalSizeBits::decode(external_data_);
+  }
+
   void SetExternalSize(intptr_t size, Isolate* isolate) {
     ASSERT(size >= 0);
     set_external_size(Utils::RoundUp(size, kObjectAlignment));
@@ -305,10 +309,6 @@
     callback_ = callback;
   }
 
-  intptr_t external_size() const {
-    return ExternalSizeBits::decode(external_data_);
-  }
-
   void set_external_size(intptr_t size) {
     ASSERT(ExternalSizeBits::is_valid(size));
     external_data_ = ExternalSizeBits::update(size, external_data_);
@@ -445,6 +445,13 @@
             kOffsetOfRawPtrInPersistentHandle>::VisitObjectPointers(visitor);
   }
 
+  // Visit all the handles.
+  void Visit(HandleVisitor* visitor) {
+    Handles<kPersistentHandleSizeInWords,
+            kPersistentHandlesPerChunk,
+            kOffsetOfRawPtrInPersistentHandle>::Visit(visitor);
+  }
+
   // Allocates a persistent handle, these have to be destroyed explicitly
   // by calling FreeHandle.
   PersistentHandle* AllocateHandle() {
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 06e7880..dda7b34 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -46,7 +46,6 @@
 
 DECLARE_FLAG(bool, trace_isolates);
 DECLARE_FLAG(bool, warn_on_pause_with_no_debugger);
-DECLARE_FLAG(bool, precompilation);
 
 
 #ifndef PRODUCT
@@ -330,7 +329,9 @@
     // If we were paused, notify the service that we have resumed.
     const Error& error =
         Error::Handle(Thread::Current()->sticky_error());
-    ASSERT(error.IsNull() || error.IsUnwindError());
+    ASSERT(error.IsNull() ||
+           error.IsUnwindError() ||
+           error.IsUnhandledException());
 
     // Only send a resume event when the isolate is not unwinding.
     if (!error.IsUnwindError()) {
@@ -1056,7 +1057,7 @@
     VariableAt(i, &name, &ignore, &ignore, &value);
     if (!name.Equals(Symbols::This())) {
       if (IsPrivateVariableName(name)) {
-        name = String::IdentifierPrettyName(name);
+        name = String::ScrubName(name);
       }
       param_names.Add(name);
       param_values.Add(value);
@@ -1129,7 +1130,7 @@
       if (var_name.raw() != Symbols::AsyncOperation().raw()) {
         JSONObject jsvar(&jsvars);
         jsvar.AddProperty("type", "BoundVariable");
-        var_name = String::IdentifierPrettyName(var_name);
+        var_name = String::ScrubName(var_name);
         jsvar.AddProperty("name", var_name.ToCString());
         jsvar.AddProperty("value", var_value, !full);
         // TODO(turnidge): Do we really want to provide this on every
@@ -1518,7 +1519,7 @@
     }
     if (frame->IsDartFrame()) {
       code = frame->LookupDartCode();
-      if (code.is_optimized() && !FLAG_precompilation) {
+      if (code.is_optimized() && !FLAG_precompiled_mode) {
         deopt_frame = DeoptimizeToArray(thread, frame, code);
         for (InlinedFunctionsIterator it(code, frame->pc());
              !it.Done();
@@ -1636,7 +1637,7 @@
 
 
 bool Debugger::ShouldPauseOnException(DebuggerStackTrace* stack_trace,
-                                      const Instance& exc) {
+                                      const Instance& exception) {
   if (exc_pause_info_ == kNoPauseOnExceptions) {
     return false;
   }
@@ -1644,7 +1645,7 @@
     return true;
   }
   ASSERT(exc_pause_info_ == kPauseOnUnhandledExceptions);
-  ActivationFrame* handler_frame = stack_trace->GetHandlerFrame(exc);
+  ActivationFrame* handler_frame = stack_trace->GetHandlerFrame(exception);
   if (handler_frame == NULL) {
     // Did not find an exception handler that catches this exception.
     // Note that this check is not precise, since we can't check
@@ -1673,8 +1674,9 @@
   }
   DebuggerEvent event(isolate_, DebuggerEvent::kExceptionThrown);
   event.set_exception(&exc);
-  ASSERT(stack_trace->Length() > 0);
-  event.set_top_frame(stack_trace->FrameAt(0));
+  if (stack_trace->Length() > 0) {
+    event.set_top_frame(stack_trace->FrameAt(0));
+  }
   ASSERT(stack_trace_ == NULL);
   stack_trace_ = stack_trace;
   Pause(&event);
diff --git a/runtime/vm/debugger_api_impl_test.cc b/runtime/vm/debugger_api_impl_test.cc
index 85faf11..0be2d29 100644
--- a/runtime/vm/debugger_api_impl_test.cc
+++ b/runtime/vm/debugger_api_impl_test.cc
@@ -11,9 +11,6 @@
 
 namespace dart {
 
-DECLARE_FLAG(bool, background_compilation);
-DECLARE_FLAG(int, optimization_counter_threshold);
-DECLARE_FLAG(bool, use_osr);
 DECLARE_FLAG(bool, trace_shutdown);
 
 #ifndef PRODUCT
diff --git a/runtime/vm/deopt_instructions.cc b/runtime/vm/deopt_instructions.cc
index a926fdf..1aa11b7 100644
--- a/runtime/vm/deopt_instructions.cc
+++ b/runtime/vm/deopt_instructions.cc
@@ -143,18 +143,21 @@
     TimelineStream* compiler_stream = isolate->GetCompilerStream();
     ASSERT(compiler_stream != NULL);
     if (compiler_stream->Enabled()) {
+      // Allocate all Dart objects needed before calling StartEvent,
+      // which blocks safe points until Complete is called.
       const Code& code = Code::Handle(zone(), code_);
       const Function& function = Function::Handle(zone(), code.function());
-      const char* function_name = function.QualifiedUserVisibleNameCString();
+      const String& function_name =
+          String::Handle(zone(), function.QualifiedScrubbedName());
       const char* reason = DeoptReasonToCString(deopt_reason());
-      int counter = function.deoptimization_counter();
+      const int counter = function.deoptimization_counter();
       TimelineEvent* timeline_event = compiler_stream->StartEvent();
       if (timeline_event != NULL) {
         timeline_event->Duration("Deoptimize",
                                  deopt_start_micros_,
                                  OS::GetCurrentMonotonicMicros());
         timeline_event->SetNumArguments(3);
-        timeline_event->CopyArgument(0, "function", function_name);
+        timeline_event->CopyArgument(0, "function", function_name.ToCString());
         timeline_event->CopyArgument(1, "reason", reason);
         timeline_event->FormatArgument(2, "deoptimizationCount", "%d", counter);
         timeline_event->Complete();
diff --git a/runtime/vm/disassembler_arm64.cc b/runtime/vm/disassembler_arm64.cc
index bf07877..a238641 100644
--- a/runtime/vm/disassembler_arm64.cc
+++ b/runtime/vm/disassembler_arm64.cc
@@ -334,6 +334,10 @@
     int reg = instr->RaField();
     PrintRegister(reg, R31IsZR);
     return 2;
+  } else if (format[1] == 's') {  // 'rs: Rs register
+    int reg = instr->RsField();
+    PrintRegister(reg, R31IsZR);
+    return 2;
   }
   UNREACHABLE();
   return -1;
@@ -742,6 +746,26 @@
 }
 
 
+void ARM64Decoder::DecodeLoadStoreExclusive(Instr* instr) {
+  if ((instr->Bit(23) != 0) ||
+      (instr->Bit(21) != 0) ||
+      (instr->Bit(15) != 0)) {
+    Unknown(instr);
+  }
+  const int32_t size = instr->Bits(30, 2);
+  if (size != 3) {
+    Unknown(instr);
+  }
+
+  const bool is_load = instr->Bit(22) == 1;
+  if (is_load) {
+    Format(instr, "ldxr 'rt, 'rn");
+  } else {
+    Format(instr, "stxr 'rs, 'rt, 'rn");
+  }
+}
+
+
 void ARM64Decoder::DecodeAddSubImm(Instr* instr) {
   switch (instr->Bit(30)) {
     case 0: {
@@ -849,6 +873,11 @@
 
 
 void ARM64Decoder::DecodeSystem(Instr* instr) {
+  if (instr->InstructionBits() == CLREX) {
+    Format(instr, "clrex");
+    return;
+  }
+
   if ((instr->Bits(0, 8) == 0x1f) && (instr->Bits(12, 4) == 2) &&
       (instr->Bits(16, 3) == 3) && (instr->Bits(19, 2) == 0) &&
       (instr->Bit(21) == 0)) {
@@ -950,6 +979,8 @@
     DecodeLoadStoreRegPair(instr);
   } else if (instr->IsLoadRegLiteralOp()) {
     DecodeLoadRegLiteral(instr);
+  } else if (instr->IsLoadStoreExclusiveOp()) {
+    DecodeLoadStoreExclusive(instr);
   } else {
     Unknown(instr);
   }
diff --git a/runtime/vm/disassembler_mips.cc b/runtime/vm/disassembler_mips.cc
index a6195fb..b9e0987 100644
--- a/runtime/vm/disassembler_mips.cc
+++ b/runtime/vm/disassembler_mips.cc
@@ -712,6 +712,10 @@
       Format(instr, "lui 'rt, 'immu");
       break;
     }
+    case LL: {
+      Format(instr, "ll 'rt, 'imms('rs)");
+      break;
+    }
     case LW: {
       Format(instr, "lw 'rt, 'imms('rs)");
       break;
@@ -728,6 +732,10 @@
       Format(instr, "sb 'rt, 'imms('rs)");
       break;
     }
+    case SC: {
+      Format(instr, "sc 'rt, 'imms('rs)");
+      break;
+    }
     case SLTI: {
       Format(instr, "slti 'rt, 'rs, 'imms");
       break;
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index 800a802..84ca377 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -64,7 +64,8 @@
  public:
   explicit PreallocatedStacktraceBuilder(const Instance& stacktrace)
   : stacktrace_(Stacktrace::Cast(stacktrace)),
-        cur_index_(0) {
+        cur_index_(0),
+        dropped_frames_(0) {
     ASSERT(stacktrace_.raw() ==
            Isolate::Current()->object_store()->preallocated_stack_trace());
   }
@@ -77,6 +78,7 @@
 
   const Stacktrace& stacktrace_;
   intptr_t cur_index_;
+  intptr_t dropped_frames_;
 
   DISALLOW_COPY_AND_ASSIGN(PreallocatedStacktraceBuilder);
 };
@@ -90,11 +92,18 @@
     Smi& frame_offset = Smi::Handle();
     intptr_t start = Stacktrace::kPreallocatedStackdepth - (kNumTopframes - 1);
     intptr_t null_slot = start - 2;
+    // We are going to drop one frame.
+    dropped_frames_++;
     // Add an empty slot to indicate the overflow so that the toString
     // method can account for the overflow.
     if (stacktrace_.FunctionAtFrame(null_slot) != Function::null()) {
       stacktrace_.SetCodeAtFrame(null_slot, frame_code);
+      // We drop an extra frame here too.
+      dropped_frames_++;
     }
+    // Encode the number of dropped frames into the pc offset.
+    frame_offset ^= Smi::New(dropped_frames_);
+    stacktrace_.SetPcOffsetAtFrame(null_slot, frame_offset);
     // Move frames one slot down so that we can accomodate the new frame.
     for (intptr_t i = start; i < Stacktrace::kPreallocatedStackdepth; i++) {
       intptr_t prev = (i - 1);
diff --git a/runtime/vm/flag_list.h b/runtime/vm/flag_list.h
index 4fdfb7b..35a7756 100644
--- a/runtime/vm/flag_list.h
+++ b/runtime/vm/flag_list.h
@@ -21,8 +21,22 @@
 //   R(name, product_value, type, default_value, comment)
 //   C(name, precompiled_value, product_value, type, default_value, comment)
 #define FLAG_LIST(P, R, D, C)                                                  \
+C(allow_absolute_addresses, false, true, bool, true,                           \
+  "Allow embedding absolute addresses in generated code.")                     \
+C(always_megamorphic_calls, true, false, bool, false,                          \
+  "Instance call always as megamorphic.")                                      \
+C(background_compilation, false, false, bool, false,                           \
+  "Run optimizing compilation in background")                                  \
+C(collect_code, false, true, bool, true,                                       \
+  "Attempt to GC infrequently used code.")                                     \
+C(collect_dynamic_function_names, true, false, bool, false,                    \
+  "Collects all dynamic function names to identify unique targets")            \
 R(dedup_instructions, true, bool, false,                                       \
   "Canonicalize instructions when precompiling.")                              \
+C(deoptimize_alot, false, false, bool, false,                                  \
+  "Deoptimizes we are about to return to Dart code from native entries.")      \
+C(deoptimize_every, 0, 0, int, 0,                                              \
+  "Deoptimize on every N stack overflow checks")                               \
 R(disable_alloc_stubs_after_gc, false, bool, false,                            \
   "Stress testing flag.")                                                      \
 R(disassemble, false, bool, false,                                             \
@@ -31,16 +45,38 @@
   "Disassemble optimized code.")                                               \
 R(dump_symbol_stats, false, bool, false,                                       \
   "Dump symbol table statistics")                                              \
-R(enable_mirrors, false, bool, true,                                           \
+C(emit_edge_counters, false, true, bool, true,                                 \
+  "Emit edge counters")                                                        \
+R(enable_asserts, false, bool, false,                                          \
+  "Enable assert statements.")                                                 \
+C(enable_mirrors, false, false, bool, true,                                    \
   "Disable to make importing dart:mirrors an error.")                          \
+R(enable_type_checks, false, bool, false,                                      \
+  "Enable type checks.")                                                       \
+R(error_on_bad_override, false, bool, false,                                   \
+  "Report error for bad overrides.")                                           \
+R(error_on_bad_type, false, bool, false,                                       \
+  "Report error for malformed types.")                                         \
+C(fields_may_be_reset, true, false, bool, false,                               \
+  "Don't optimize away static field initialization")                           \
+C(force_clone_compiler_objects, false, false, bool, false,                     \
+  "Force cloning of objects needed in compiler (ICData and Field).")           \
 R(gc_at_alloc, false, bool, false,                                             \
   "GC at every allocation.")                                                   \
 P(getter_setter_ratio, int, 13,                                                \
   "Ratio of getter/setter usage used for double field unboxing heuristics")    \
 P(guess_icdata_cid, bool, true,                                                \
   "Artificially create type feedback for arithmetic etc. operations")          \
+C(ic_range_profiling, false, true, bool, true,                                 \
+  "Generate special IC stubs collecting range information ")                   \
+C(interpret_irregexp, true, false, bool, false,                                \
+  "Use irregexp bytecode interpreter")                                         \
 C(lazy_dispatchers, false, true, bool, true,                                   \
   "Generate dispatchers lazily")                                               \
+C(link_natives_lazily, true, false, bool, false,                               \
+  "Link native calls lazily")                                                  \
+C(load_deferred_eagerly, true, true, bool, false,                              \
+  "Load deferred libraries eagerly.")                                          \
 P(max_polymorphic_checks, int, 4,                                              \
   "Maximum number of polymorphic check, otherwise it is megamorphic.")         \
 P(max_equality_polymorphic_checks, int, 32,                                    \
@@ -49,14 +85,20 @@
   "Merge sin/cos into sincos")                                                 \
 P(new_gen_ext_limit, int, 64,                                                  \
   "maximum total external size (MB) in new gen before triggering GC")          \
+C(optimization_counter_threshold, -1, 30000, int, 30000,                       \
+  "Function's usage-counter value before it is optimized, -1 means never")     \
 C(polymorphic_with_deopt, false, true, bool, true,                             \
-    "Polymorphic calls with deoptimization / megamorphic call")                \
+  "Polymorphic calls with deoptimization / megamorphic call")                  \
+C(precompiled_mode, true, false, bool, false,                                  \
+  "Precompilation compiler/runtime mode")                                      \
 R(pretenure_all, false, bool, false,                                           \
   "Global pretenuring (for testing).")                                         \
 P(pretenure_interval, int, 10,                                                 \
   "Back off pretenuring after this many cycles.")                              \
 P(pretenure_threshold, int, 98,                                                \
   "Trigger pretenuring when this many percent are promoted.")                  \
+C(print_stop_message, false, false, bool, false,                               \
+  "Print stop message.")                                                       \
 R(profiler, false, bool, true,                                                 \
   "Enable the profiler.")                                                      \
 R(support_ast_printer, false, bool, true,                                      \
@@ -89,6 +131,10 @@
   "Optimize left shift to truncate if possible")                               \
 C(use_cha_deopt, false, true, bool, true,                                      \
   "Use class hierarchy analysis even if it can cause deoptimization.")         \
+C(use_field_guards, false, true, bool, true,                                   \
+  "Use field guards and track field types")                                    \
+C(use_osr, false, true, bool, true,                                            \
+  "Use OSR")                                                                   \
 P(verbose_gc, bool, false,                                                     \
   "Enables verbose GC.")                                                       \
 P(verbose_gc_hdr, int, 40,                                                     \
@@ -98,5 +144,4 @@
 R(verify_before_gc, false, bool, false,                                        \
   "Enables heap verification before GC.")                                      \
 
-
 #endif  // VM_FLAG_LIST_H_
diff --git a/runtime/vm/flags.cc b/runtime/vm/flags.cc
index ee7d702..cb76c91 100644
--- a/runtime/vm/flags.cc
+++ b/runtime/vm/flags.cc
@@ -80,6 +80,7 @@
 #undef PRODUCT_FLAG_MARCO
 #undef PRECOMPILE_FLAG_MARCO
 
+
 bool Flags::initialized_ = false;
 
 // List of registered flags.
diff --git a/runtime/vm/flow_graph.cc b/runtime/vm/flow_graph.cc
index b7b59cd..3296e09 100644
--- a/runtime/vm/flow_graph.cc
+++ b/runtime/vm/flow_graph.cc
@@ -19,7 +19,6 @@
 DEFINE_FLAG(bool, trace_smi_widening, false, "Trace Smi->Int32 widening pass.");
 #endif
 DEFINE_FLAG(bool, prune_dead_locals, true, "optimize dead locals away");
-DECLARE_FLAG(bool, emit_edge_counters);
 DECLARE_FLAG(bool, reorder_basic_blocks);
 DECLARE_FLAG(bool, verify_compiler);
 
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index 736efc6..c5460be 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -39,9 +39,7 @@
 DEFINE_FLAG(bool, trace_type_check_elimination, false,
             "Trace type check elimination at compile time.");
 
-DECLARE_FLAG(int, optimization_counter_threshold);
 DECLARE_FLAG(bool, profile_vm);
-DECLARE_FLAG(bool, use_field_guards);
 
 // Quick access to the locally defined zone() method.
 #define Z (zone())
@@ -995,7 +993,7 @@
 
 void TestGraphVisitor::ReturnValue(Value* value) {
   Isolate* isolate = Isolate::Current();
-  if (isolate->flags().type_checks() || isolate->flags().asserts()) {
+  if (isolate->type_checks() || isolate->asserts()) {
     value = Bind(new(Z) AssertBooleanInstr(condition_token_pos(), value));
   }
   Value* constant_true = Bind(new(Z) ConstantInstr(Bool::True()));
@@ -1030,7 +1028,7 @@
         false));  // No number check.
   } else {
     branch = new(Z) BranchInstr(comp);
-    branch->set_is_checked(Isolate::Current()->flags().type_checks());
+    branch->set_is_checked(Isolate::Current()->type_checks());
   }
   AddInstruction(branch);
   CloseFragment();
@@ -1040,7 +1038,7 @@
 
 
 void TestGraphVisitor::MergeBranchWithNegate(BooleanNegateInstr* neg) {
-  ASSERT(!Isolate::Current()->flags().type_checks());
+  ASSERT(!Isolate::Current()->type_checks());
   Value* constant_true = Bind(new(Z) ConstantInstr(Bool::True()));
   StrictCompareInstr* comp =
       new(Z) StrictCompareInstr(condition_token_pos(),
@@ -1062,7 +1060,7 @@
     MergeBranchWithComparison(comp);
     return;
   }
-  if (!Isolate::Current()->flags().type_checks()) {
+  if (!Isolate::Current()->type_checks()) {
     BooleanNegateInstr* neg = definition->AsBooleanNegate();
     if (neg != NULL) {
       MergeBranchWithNegate(neg);
@@ -1155,7 +1153,7 @@
     return_value = Bind(BuildLoadLocal(*temp, node->token_pos()));
   }
 
-  if (Isolate::Current()->flags().type_checks()) {
+  if (Isolate::Current()->type_checks()) {
     const bool is_implicit_dynamic_getter =
         (!function.is_static() &&
         ((function.kind() == RawFunction::kImplicitGetter) ||
@@ -1356,7 +1354,7 @@
     node->left()->Visit(&for_left);
     EffectGraphVisitor empty(owner());
     Isolate* isolate = Isolate::Current();
-    if (isolate->flags().type_checks() || isolate->flags().asserts()) {
+    if (isolate->type_checks() || isolate->asserts()) {
       ValueGraphVisitor for_right(owner());
       node->right()->Visit(&for_right);
       Value* right_value = for_right.value();
@@ -1423,7 +1421,7 @@
     node->right()->Visit(&for_right);
     Value* right_value = for_right.value();
     Isolate* isolate = Isolate::Current();
-    if (isolate->flags().type_checks() || isolate->flags().asserts()) {
+    if (isolate->type_checks() || isolate->asserts()) {
       right_value =
           for_right.Bind(new(Z) AssertBooleanInstr(node->right()->token_pos(),
                                                    right_value));
@@ -1802,7 +1800,7 @@
         owner()->ic_data_array());
     if (node->kind() == Token::kNE) {
       Isolate* isolate = Isolate::Current();
-      if (isolate->flags().type_checks() || isolate->flags().asserts()) {
+      if (isolate->type_checks() || isolate->asserts()) {
         Value* value = Bind(result);
         result = new(Z) AssertBooleanInstr(node->token_pos(), value);
       }
@@ -1849,7 +1847,7 @@
     Append(for_value);
     Value* value = for_value.value();
     Isolate* isolate = Isolate::Current();
-    if (isolate->flags().type_checks() || isolate->flags().asserts()) {
+    if (isolate->type_checks() || isolate->asserts()) {
       value =
           Bind(new(Z) AssertBooleanInstr(node->operand()->token_pos(), value));
     }
@@ -2772,7 +2770,8 @@
 
 
 void EffectGraphVisitor::VisitInitStaticFieldNode(InitStaticFieldNode* node) {
-  Value* field = Bind(new(Z) ConstantInstr(node->field()));
+  Value* field = Bind(new(Z) ConstantInstr(
+      Field::ZoneHandle(Z, node->field().Original())));
   AddInstruction(new(Z) InitStaticFieldInstr(field, node->field()));
 }
 
@@ -3644,7 +3643,7 @@
   node->value()->Visit(&for_value);
   Append(for_value);
   Value* store_value = for_value.value();
-  if (Isolate::Current()->flags().type_checks()) {
+  if (Isolate::Current()->type_checks()) {
     store_value = BuildAssignableValue(node->value()->token_pos(),
                                        store_value,
                                        node->local().type(),
@@ -3688,7 +3687,7 @@
   node->value()->Visit(&for_value);
   Append(for_value);
   Value* store_value = for_value.value();
-  if (Isolate::Current()->flags().type_checks()) {
+  if (Isolate::Current()->type_checks()) {
     const AbstractType& type =
         AbstractType::ZoneHandle(Z, node->field().type());
     const String& dst_name = String::ZoneHandle(Z, node->field().name());
@@ -3735,7 +3734,8 @@
         Instance::ZoneHandle(Z, node->field().StaticValue()), token_pos);
     return ReturnDefinition(result);
   }
-  Value* field_value = Bind(new(Z) ConstantInstr(node->field(), token_pos));
+  Value* field_value = Bind(new(Z) ConstantInstr(
+      Field::ZoneHandle(Z, node->field().Original()), token_pos));
   LoadStaticFieldInstr* load =
       new(Z) LoadStaticFieldInstr(field_value, token_pos);
   ReturnDefinition(load);
@@ -4118,7 +4118,7 @@
     }
   }
 
-  if (Isolate::Current()->flags().type_checks() && is_top_level_sequence) {
+  if (Isolate::Current()->type_checks() && is_top_level_sequence) {
     const int num_params = function.NumParameters();
     int pos = 0;
     if (function.IsFactory() ||
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index d646909..5bc26af 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -30,10 +30,6 @@
 
 namespace dart {
 
-DEFINE_FLAG(bool, allow_absolute_addresses, true,
-    "Allow embedding absolute addresses in generated code.");
-DEFINE_FLAG(bool, always_megamorphic_calls, false,
-    "Instance call always as megamorphic.");
 DEFINE_FLAG(bool, enable_simd_inline, true,
     "Enable inlining of SIMD related method calls.");
 DEFINE_FLAG(int, min_optimization_counter_threshold, 5000,
@@ -45,28 +41,14 @@
     "Inlining interval diagnostics");
 DEFINE_FLAG(bool, use_megamorphic_stub, true, "Out of line megamorphic lookup");
 
-DECLARE_FLAG(bool, background_compilation);
 DECLARE_FLAG(bool, code_comments);
-DECLARE_FLAG(bool, collect_dynamic_function_names);
-DECLARE_FLAG(bool, deoptimize_alot);
-DECLARE_FLAG(int, deoptimize_every);
 DECLARE_FLAG(charp, deoptimize_filter);
-DECLARE_FLAG(bool, emit_edge_counters);
-DECLARE_FLAG(bool, fields_may_be_reset);
-DECLARE_FLAG(bool, ic_range_profiling);
 DECLARE_FLAG(bool, intrinsify);
-DECLARE_FLAG(bool, load_deferred_eagerly);
-DECLARE_FLAG(int, optimization_counter_threshold);
 DECLARE_FLAG(bool, propagate_ic_data);
 DECLARE_FLAG(int, regexp_optimization_counter_threshold);
 DECLARE_FLAG(int, reoptimization_counter_threshold);
 DECLARE_FLAG(int, stacktrace_every);
 DECLARE_FLAG(charp, stacktrace_filter);
-DECLARE_FLAG(bool, use_field_guards);
-DECLARE_FLAG(bool, use_osr);
-DECLARE_FLAG(bool, print_stop_message);
-DECLARE_FLAG(bool, interpret_irregexp);
-DECLARE_FLAG(bool, link_natives_lazily);
 DECLARE_FLAG(bool, trace_compiler);
 DECLARE_FLAG(int, inlining_hotness);
 DECLARE_FLAG(int, inlining_size_threshold);
@@ -77,39 +59,19 @@
 DECLARE_FLAG(int, inlining_constant_arguments_max_size_threshold);
 DECLARE_FLAG(int, inlining_constant_arguments_min_size_threshold);
 
-bool FLAG_precompilation = false;
+#if !defined(DART_PRECOMPILED_RUNTIME)
 static void PrecompilationModeHandler(bool value) {
   if (value) {
 #if defined(TARGET_ARCH_IA32)
     FATAL("Precompilation not supported on IA32");
 #endif
-    FLAG_precompilation = true;
 
-    FLAG_always_megamorphic_calls = true;
-    FLAG_optimization_counter_threshold = -1;
-    FLAG_use_field_guards = false;
-    FLAG_use_osr = false;
-    FLAG_emit_edge_counters = false;
-#ifndef PRODUCT
+#if defined(PRODUCT)
+    FATAL("dart_noopt not supported in product mode");
+#else
     FLAG_support_debugger = false;
-#endif  // !PRODUCT
-    FLAG_ic_range_profiling = false;
-    FLAG_collect_code = false;
-    FLAG_load_deferred_eagerly = true;
-    FLAG_deoptimize_alot = false;  // Used in some tests.
-    FLAG_deoptimize_every = 0;     // Used in some tests.
-    // Calling the PrintStopMessage stub is not supported in precompiled code
-    // since it is done at places where no pool pointer is loaded.
-    FLAG_print_stop_message = false;
 
-    FLAG_interpret_irregexp = true;
-#ifndef PRODUCT
-    FLAG_enable_mirrors = false;
-#endif  // !PRODUCT
-    FLAG_link_natives_lazily = true;
-    FLAG_fields_may_be_reset = true;
-    FLAG_allow_absolute_addresses = false;
-
+    // Flags affecting compilation only:
     // There is no counter feedback in precompilation, so ignore the counter
     // when making inlining decisions.
     FLAG_inlining_hotness = 0;
@@ -120,39 +82,66 @@
     FLAG_inlining_callee_size_threshold = 20;
     FLAG_inlining_depth_threshold = 2;
     FLAG_inlining_caller_size_threshold = 1000;
-
     FLAG_inlining_constant_arguments_max_size_threshold = 100;
     FLAG_inlining_constant_arguments_min_size_threshold = 30;
 
-    // Background compilation relies on two-stage compilation pipeline,
-    // while precompilation has only one.
+    FLAG_allow_absolute_addresses = false;
+    FLAG_always_megamorphic_calls = true;
     FLAG_background_compilation = false;
+    FLAG_collect_code = false;
     FLAG_collect_dynamic_function_names = true;
-#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(PRODUCT)
+    FLAG_deoptimize_alot = false;  // Used in some tests.
+    FLAG_deoptimize_every = 0;     // Used in some tests.
+    FLAG_emit_edge_counters = false;
+    FLAG_enable_mirrors = false;
+    FLAG_fields_may_be_reset = true;
+    FLAG_ic_range_profiling = false;
+    FLAG_interpret_irregexp = true;
     FLAG_lazy_dispatchers = false;
+    FLAG_link_natives_lazily = true;
+    FLAG_load_deferred_eagerly = true;
+    FLAG_optimization_counter_threshold = -1;
     FLAG_polymorphic_with_deopt = false;
-    // Precompilation finalizes all classes and thus allows CHA optimizations.
-    // Do not require CHA triggered deoptimization.
+    FLAG_precompiled_mode = true;
+    FLAG_print_stop_message = false;
     FLAG_use_cha_deopt = false;
-#elif defined(DART_PRECOMPILED_RUNTIME)
-    // Precompiled product and release mode.
-    COMPILE_ASSERT(!FLAG_lazy_dispatchers);
-    COMPILE_ASSERT(!FLAG_polymorphic_with_deopt);
-    COMPILE_ASSERT(!FLAG_use_cha_deopt);
-#elif defined(PRODUCT)
-    // Jit product and release mode.
-    COMPILE_ASSERT(FLAG_lazy_dispatchers);
-    COMPILE_ASSERT(FLAG_polymorphic_with_deopt);
-    COMPILE_ASSERT(FLAG_use_cha_deopt);
-#endif
+    FLAG_use_field_guards = false;
+    FLAG_use_osr = false;
+#endif  // PRODUCT
   }
 }
 
-
 DEFINE_FLAG_HANDLER(PrecompilationModeHandler,
                     precompilation,
                     "Precompilation mode");
 
+#else  // DART_PRECOMPILED_RUNTIME
+
+COMPILE_ASSERT(!FLAG_allow_absolute_addresses);
+COMPILE_ASSERT(!FLAG_background_compilation);
+COMPILE_ASSERT(!FLAG_collect_code);
+COMPILE_ASSERT(!FLAG_deoptimize_alot);  // Used in some tests.
+COMPILE_ASSERT(!FLAG_emit_edge_counters);
+COMPILE_ASSERT(!FLAG_enable_mirrors);
+COMPILE_ASSERT(!FLAG_ic_range_profiling);
+COMPILE_ASSERT(!FLAG_lazy_dispatchers);
+COMPILE_ASSERT(!FLAG_polymorphic_with_deopt);
+COMPILE_ASSERT(!FLAG_print_stop_message);
+COMPILE_ASSERT(!FLAG_use_cha_deopt);
+COMPILE_ASSERT(!FLAG_use_field_guards);
+COMPILE_ASSERT(!FLAG_use_osr);
+COMPILE_ASSERT(FLAG_always_megamorphic_calls);
+COMPILE_ASSERT(FLAG_collect_dynamic_function_names);
+COMPILE_ASSERT(FLAG_deoptimize_every == 0);  // Used in some tests.
+COMPILE_ASSERT(FLAG_fields_may_be_reset);
+COMPILE_ASSERT(FLAG_interpret_irregexp);
+COMPILE_ASSERT(FLAG_link_natives_lazily);
+COMPILE_ASSERT(FLAG_load_deferred_eagerly);
+COMPILE_ASSERT(FLAG_optimization_counter_threshold == -1);
+COMPILE_ASSERT(FLAG_precompiled_mode);
+
+#endif  // DART_PRECOMPILED_RUNTIME
+
 
 // Assign locations to incoming arguments, i.e., values pushed above spill slots
 // with PushArgument.  Recursively allocates from outermost to innermost
@@ -190,6 +179,7 @@
     const ParsedFunction& parsed_function,
     bool is_optimizing,
     const GrowableArray<const Function*>& inline_id_to_function,
+    const GrowableArray<TokenPosition>& inline_id_to_token_pos,
     const GrowableArray<intptr_t>& caller_inline_id)
       : thread_(Thread::Current()),
         zone_(Thread::Current()->zone()),
@@ -201,6 +191,8 @@
         exception_handlers_list_(NULL),
         pc_descriptors_list_(NULL),
         stackmap_table_builder_(NULL),
+        code_source_map_builder_(NULL),
+        saved_code_size_(0),
         block_info_(block_order_.length()),
         deopt_infos_(),
         static_calls_target_table_(),
@@ -227,6 +219,7 @@
         edge_counters_array_(Array::ZoneHandle()),
         inlined_code_intervals_(Array::ZoneHandle(Object::empty_array().raw())),
         inline_id_to_function_(inline_id_to_function),
+        inline_id_to_token_pos_(inline_id_to_token_pos),
         caller_inline_id_(caller_inline_id) {
   ASSERT(flow_graph->parsed_function().function().raw() ==
          parsed_function.function().raw());
@@ -285,9 +278,7 @@
   block_info_.Clear();
   // Conservative detection of leaf routines used to remove the stack check
   // on function entry.
-  bool is_leaf = !parsed_function().function().IsClosureFunction()
-      && is_optimizing()
-      && !flow_graph().IsCompiledForOsr();
+  bool is_leaf = is_optimizing() && !flow_graph().IsCompiledForOsr();
   // Initialize block info and search optimized (non-OSR) code for calls
   // indicating a non-leaf routine and calls without IC data indicating
   // possible reoptimization.
@@ -488,12 +479,16 @@
 
 // We collect intervals while generating code.
 struct IntervalStruct {
-  // 'start' and 'end' are pc-offsets.
+  // 'start' is the pc-offsets where the inlined code started.
+  // 'pos' is the token position where the inlined call occured.
   intptr_t start;
+  TokenPosition pos;
   intptr_t inlining_id;
-  IntervalStruct(intptr_t s, intptr_t id) : start(s), inlining_id(id) {}
+  IntervalStruct(intptr_t s, TokenPosition tp, intptr_t id)
+      : start(s), pos(tp), inlining_id(id) {}
   void Dump() {
-    THR_Print("start: 0x%" Px " iid: %" Pd " ",  start, inlining_id);
+    THR_Print("start: 0x%" Px " iid: %" Pd " pos: %s",
+              start, inlining_id, pos.ToCString());
   }
 };
 
@@ -511,6 +506,7 @@
   GrowableArray<IntervalStruct> intervals;
   intptr_t prev_offset = 0;
   intptr_t prev_inlining_id = 0;
+  TokenPosition prev_inlining_pos = parsed_function_.function().token_pos();
   intptr_t max_inlining_id = 0;
   for (intptr_t i = 0; i < block_order().length(); ++i) {
     // Compile the block entry.
@@ -531,16 +527,20 @@
     LoopInfoComment(assembler(), *entry, *loop_headers);
 
     entry->set_offset(assembler()->CodeSize());
+    BeginCodeSourceRange();
     entry->EmitNativeCode(this);
+    EndCodeSourceRange(entry->token_pos());
     // Compile all successors until an exit, branch, or a block entry.
     for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) {
       Instruction* instr = it.Current();
       // Compose intervals.
       if (instr->has_inlining_id() && is_optimizing()) {
         if (prev_inlining_id != instr->inlining_id()) {
-          intervals.Add(IntervalStruct(prev_offset, prev_inlining_id));
+          intervals.Add(
+              IntervalStruct(prev_offset, prev_inlining_pos, prev_inlining_id));
           prev_offset = assembler()->CodeSize();
           prev_inlining_id = instr->inlining_id();
+          prev_inlining_pos = inline_id_to_token_pos_[prev_inlining_id];
           if (prev_inlining_id > max_inlining_id) {
             max_inlining_id = prev_inlining_id;
           }
@@ -556,12 +556,14 @@
       if (instr->IsParallelMove()) {
         parallel_move_resolver_.EmitNativeCode(instr->AsParallelMove());
       } else {
+        BeginCodeSourceRange();
         EmitInstructionPrologue(instr);
         ASSERT(pending_deoptimization_env_ == NULL);
         pending_deoptimization_env_ = instr->env();
         instr->EmitNativeCode(this);
         pending_deoptimization_env_ = NULL;
         EmitInstructionEpilogue(instr);
+        EndCodeSourceRange(instr->token_pos());
       }
 
 #if defined(DEBUG)
@@ -578,7 +580,8 @@
 
   if (is_optimizing()) {
     LogBlock lb;
-    intervals.Add(IntervalStruct(prev_offset, prev_inlining_id));
+    intervals.Add(
+        IntervalStruct(prev_offset, prev_inlining_pos, prev_inlining_id));
     inlined_code_intervals_ =
         Array::New(intervals.length() * Code::kInlIntNumEntries, Heap::kOld);
     Smi& start_h = Smi::Handle();
@@ -738,10 +741,14 @@
 
 void FlowGraphCompiler::GenerateDeferredCode() {
   for (intptr_t i = 0; i < slow_path_code_.length(); i++) {
+    BeginCodeSourceRange();
     slow_path_code_[i]->GenerateCode(this);
+    EndCodeSourceRange(TokenPosition::kDeferredSlowPath);
   }
   for (intptr_t i = 0; i < deopt_infos_.length(); i++) {
+    BeginCodeSourceRange();
     deopt_infos_[i]->GenerateCode(this, i);
+    EndCodeSourceRange(TokenPosition::kDeferredDeoptInfo);
   }
 }
 
@@ -942,8 +949,8 @@
     return &intrinsic_slow_path_label_;
   }
 
-  // No deoptimization allowed when 'FLAG_precompilation' is set.
-  if (FLAG_precompilation) {
+  // No deoptimization allowed when 'FLAG_precompiled_mode' is set.
+  if (FLAG_precompiled_mode) {
     if (FLAG_trace_compiler) {
       THR_Print(
           "Retrying compilation %s, suppressing inlining of deopt_id:%" Pd "\n",
@@ -991,7 +998,7 @@
 
 RawArray* FlowGraphCompiler::CreateDeoptInfo(Assembler* assembler) {
   // No deopt information if we precompile (no deoptimization allowed).
-  if (FLAG_precompilation) {
+  if (FLAG_precompiled_mode) {
     return Array::empty_array().raw();
   }
   // For functions with optional arguments, all incoming arguments are copied
@@ -1091,7 +1098,7 @@
 bool FlowGraphCompiler::TryIntrinsify() {
   // Intrinsification skips arguments checks, therefore disable if in checked
   // mode.
-  if (FLAG_intrinsify && !isolate()->flags().type_checks()) {
+  if (FLAG_intrinsify && !isolate()->type_checks()) {
     if (parsed_function().function().kind() == RawFunction::kImplicitGetter) {
       // An implicit getter must have a specific AST structure.
       const SequenceNode& sequence_node = *parsed_function().node_sequence();
@@ -1148,7 +1155,7 @@
     LocationSummary* locs,
     const ICData& ic_data_in) {
   const ICData& ic_data = ICData::ZoneHandle(ic_data_in.Original());
-  if (FLAG_precompilation) {
+  if (FLAG_precompiled_mode) {
     EmitSwitchableInstanceCall(ic_data, argument_count,
                                deopt_id, token_pos, locs);
     return;
@@ -1438,7 +1445,9 @@
     const MoveOperands& move = *moves_[i];
     if (!move.IsEliminated()) {
       ASSERT(move.src().IsConstant());
+      compiler_->BeginCodeSourceRange();
       EmitMove(i);
+      compiler_->EndCodeSourceRange(TokenPosition::kParallelMove);
     }
   }
 
@@ -1514,13 +1523,17 @@
     const MoveOperands& other_move = *moves_[i];
     if (other_move.Blocks(destination)) {
       ASSERT(other_move.IsPending());
+      compiler_->BeginCodeSourceRange();
       EmitSwap(index);
+      compiler_->EndCodeSourceRange(TokenPosition::kParallelMove);
       return;
     }
   }
 
   // This move is not blocked.
+  compiler_->BeginCodeSourceRange();
   EmitMove(index);
+  compiler_->EndCodeSourceRange(TokenPosition::kParallelMove);
 }
 
 
@@ -1763,6 +1776,21 @@
 }
 
 
+RawArray* FlowGraphCompiler::InliningIdToTokenPos() const {
+  if (inline_id_to_token_pos_.length() == 0) {
+    return Object::empty_array().raw();
+  }
+  const Array& res = Array::Handle(zone(),
+      Array::New(inline_id_to_token_pos_.length(), Heap::kOld));
+  Smi& smi = Smi::Handle(zone());
+  for (intptr_t i = 0; i < inline_id_to_token_pos_.length(); i++) {
+    smi = Smi::New(inline_id_to_token_pos_[i].value());
+    res.SetAt(i, smi);
+  }
+  return res.raw();
+}
+
+
 RawArray* FlowGraphCompiler::CallerInliningIdMap() const {
   if (caller_inline_id_.length() == 0) {
     return Object::empty_array().raw();
@@ -1778,6 +1806,30 @@
 }
 
 
+void FlowGraphCompiler::BeginCodeSourceRange() {
+NOT_IN_PRODUCT(
+  // Remember how many bytes of code we emitted so far. This function
+  // is called before we call into an instruction's EmitNativeCode.
+  saved_code_size_ = assembler()->CodeSize();
+);
+}
+
+
+bool FlowGraphCompiler::EndCodeSourceRange(TokenPosition token_pos) {
+NOT_IN_PRODUCT(
+  // This function is called after each instructions' EmitNativeCode.
+  if (saved_code_size_ < assembler()->CodeSize()) {
+    // We emitted more code, now associate the emitted code chunk with
+    // |token_pos|.
+    code_source_map_builder()->AddEntry(saved_code_size_, token_pos);
+    BeginCodeSourceRange();
+    return true;
+  }
+);
+  return false;
+}
+
+
 void FlowGraphCompiler::EmitPolymorphicInstanceCall(
     const ICData& ic_data,
     intptr_t argument_count,
diff --git a/runtime/vm/flow_graph_compiler.h b/runtime/vm/flow_graph_compiler.h
index 7a1e156..60ce384 100644
--- a/runtime/vm/flow_graph_compiler.h
+++ b/runtime/vm/flow_graph_compiler.h
@@ -302,6 +302,7 @@
       const ParsedFunction& parsed_function,
       bool is_optimizing,
       const GrowableArray<const Function*>& inline_id_to_function,
+      const GrowableArray<TokenPosition>& inline_id_to_token_pos,
       const GrowableArray<intptr_t>& caller_inline_id);
 
   ~FlowGraphCompiler();
@@ -382,6 +383,12 @@
                         const StubEntry& stub_entry,
                         RawPcDescriptors::Kind kind,
                         LocationSummary* locs);
+  void GenerateStaticDartCall(intptr_t deopt_id,
+                              TokenPosition token_pos,
+                              const StubEntry& stub_entry,
+                              RawPcDescriptors::Kind kind,
+                              LocationSummary* locs,
+                              const Function& target);
 
   void GenerateAssertAssignable(TokenPosition token_pos,
                                 intptr_t deopt_id,
@@ -584,9 +591,20 @@
   }
 
   RawArray* InliningIdToFunction() const;
-
+  RawArray* InliningIdToTokenPos() const;
   RawArray* CallerInliningIdMap() const;
 
+  CodeSourceMapBuilder* code_source_map_builder() {
+    if (code_source_map_builder_ == NULL) {
+      code_source_map_builder_ = new CodeSourceMapBuilder();
+    }
+    ASSERT(code_source_map_builder_ != NULL);
+    return code_source_map_builder_;
+  }
+
+  void BeginCodeSourceRange();
+  bool EndCodeSourceRange(TokenPosition token_pos);
+
  private:
   friend class CheckStackOverflowSlowPath;  // For pending_deoptimization_env_.
 
@@ -744,6 +762,8 @@
   ExceptionHandlerList* exception_handlers_list_;
   DescriptorList* pc_descriptors_list_;
   StackmapTableBuilder* stackmap_table_builder_;
+  CodeSourceMapBuilder* code_source_map_builder_;
+  intptr_t saved_code_size_;
   GrowableArray<BlockInfo*> block_info_;
   GrowableArray<CompilerDeoptInfo*> deopt_infos_;
   GrowableArray<SlowPathCode*> slow_path_code_;
@@ -781,6 +801,7 @@
 
   Array& inlined_code_intervals_;
   const GrowableArray<const Function*>& inline_id_to_function_;
+  const GrowableArray<TokenPosition>& inline_id_to_token_pos_;
   const GrowableArray<intptr_t>& caller_inline_id_;
 
   DISALLOW_COPY_AND_ASSIGN(FlowGraphCompiler);
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index 2b14545..8d6816a 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -29,7 +29,6 @@
 DEFINE_FLAG(bool, unbox_doubles, true, "Optimize double arithmetic.");
 DECLARE_FLAG(bool, enable_simd_inline);
 DECLARE_FLAG(bool, use_megamorphic_stub);
-DECLARE_FLAG(bool, precompilation);
 
 
 void MegamorphicSlowPath::EmitNativeCode(FlowGraphCompiler* compiler) {
@@ -1128,13 +1127,15 @@
     }
   }
 
+  EndCodeSourceRange(TokenPosition::kDartCodePrologue);
   VisitBlocks();
 
   __ bkpt(0);
   ASSERT(assembler()->constant_pool_allowed());
   GenerateDeferredCode();
 
-  if (is_optimizing() && !FLAG_precompilation) {
+  BeginCodeSourceRange();
+  if (is_optimizing() && !FLAG_precompiled_mode) {
     // Leave enough space for patching in case of lazy deoptimization from
     // deferred code.
     for (intptr_t i = 0;
@@ -1145,6 +1146,7 @@
     lazy_deopt_pc_offset_ = assembler()->CodeSize();
     __ Branch(*StubCode::DeoptimizeLazy_entry());
   }
+  EndCodeSourceRange(TokenPosition::kDartCodeEpilogue);
 }
 
 
@@ -1180,6 +1182,35 @@
 }
 
 
+void FlowGraphCompiler::GenerateStaticDartCall(intptr_t deopt_id,
+                                               TokenPosition token_pos,
+                                               const StubEntry& stub_entry,
+                                               RawPcDescriptors::Kind kind,
+                                               LocationSummary* locs,
+                                               const Function& target) {
+  // Call sites to the same target can share object pool entries. These
+  // call sites are never patched for breakpoints: the function is deoptimized
+  // and the unoptimized code with IC calls for static calls is patched instead.
+  ASSERT(is_optimizing());
+  __ BranchLinkWithEquivalence(stub_entry, target);
+
+  AddCurrentDescriptor(kind, deopt_id, token_pos);
+  RecordSafepoint(locs);
+  // Marks either the continuation point in unoptimized code or the
+  // deoptimization point in optimized code, after call.
+  const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id);
+  if (is_optimizing()) {
+    AddDeoptIndexAtCall(deopt_id_after, token_pos);
+  } else {
+    // Add deoptimization continuation point after the call and before the
+    // arguments are removed.
+    AddCurrentDescriptor(RawPcDescriptors::kDeopt,
+        deopt_id_after, token_pos);
+  }
+  AddStaticCallTarget(target);
+}
+
+
 void FlowGraphCompiler::GenerateRuntimeCall(TokenPosition token_pos,
                                             intptr_t deopt_id,
                                             const RuntimeEntry& entry,
@@ -1298,7 +1329,7 @@
 
   RecordSafepoint(locs);
   const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id);
-  if (FLAG_precompilation) {
+  if (FLAG_precompiled_mode) {
     // Megamorphic calls may occur in slow path stubs.
     // If valid use try_index argument.
     if (try_index == CatchClauseNode::kInvalidTryIndex) {
@@ -1393,12 +1424,12 @@
   __ LoadObject(R4, arguments_descriptor);
   // Do not use the code from the function, but let the code be patched so that
   // we can record the outgoing edges to other code.
-  GenerateDartCall(deopt_id,
-                   token_pos,
-                   *StubCode::CallStaticFunction_entry(),
-                   RawPcDescriptors::kOther,
-                   locs);
-  AddStaticCallTarget(function);
+  GenerateStaticDartCall(deopt_id,
+                         token_pos,
+                         *StubCode::CallStaticFunction_entry(),
+                         RawPcDescriptors::kOther,
+                         locs,
+                         function);
   __ Drop(argument_count);
 }
 
@@ -1591,14 +1622,14 @@
     }
     // Do not use the code from the function, but let the code be patched so
     // that we can record the outgoing edges to other code.
-    GenerateDartCall(deopt_id,
-                     token_index,
-                     *StubCode::CallStaticFunction_entry(),
-                     RawPcDescriptors::kOther,
-                     locs);
     const Function& function = Function::ZoneHandle(
         zone(), ic_data.GetTargetAt(0));
-    AddStaticCallTarget(function);
+    GenerateStaticDartCall(deopt_id,
+                           token_index,
+                           *StubCode::CallStaticFunction_entry(),
+                           RawPcDescriptors::kOther,
+                           locs,
+                           function);
     __ Drop(argument_count);
     if (kNumChecks > 1) {
       __ b(match_found);
@@ -1633,13 +1664,13 @@
     }
     // Do not use the code from the function, but let the code be patched so
     // that we can record the outgoing edges to other code.
-    GenerateDartCall(deopt_id,
-                     token_index,
-                     *StubCode::CallStaticFunction_entry(),
-                     RawPcDescriptors::kOther,
-                     locs);
     const Function& function = *sorted[i].target;
-    AddStaticCallTarget(function);
+    GenerateStaticDartCall(deopt_id,
+                           token_index,
+                           *StubCode::CallStaticFunction_entry(),
+                           RawPcDescriptors::kOther,
+                           locs,
+                           function);
     __ Drop(argument_count);
     if (!kIsLastCheck) {
       __ b(match_found);
diff --git a/runtime/vm/flow_graph_compiler_arm64.cc b/runtime/vm/flow_graph_compiler_arm64.cc
index 30e4211..618e60d 100644
--- a/runtime/vm/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/flow_graph_compiler_arm64.cc
@@ -26,7 +26,6 @@
 DEFINE_FLAG(bool, trap_on_deoptimization, false, "Trap on deoptimization.");
 DECLARE_FLAG(bool, enable_simd_inline);
 DECLARE_FLAG(bool, use_megamorphic_stub);
-DECLARE_FLAG(bool, precompilation);
 
 
 void MegamorphicSlowPath::EmitNativeCode(FlowGraphCompiler* compiler) {
@@ -1121,13 +1120,15 @@
     }
   }
 
+  EndCodeSourceRange(TokenPosition::kDartCodePrologue);
   VisitBlocks();
 
   __ brk(0);
   ASSERT(assembler()->constant_pool_allowed());
   GenerateDeferredCode();
 
-  if (is_optimizing() && !FLAG_precompilation) {
+  BeginCodeSourceRange();
+  if (is_optimizing() && !FLAG_precompiled_mode) {
     // Leave enough space for patching in case of lazy deoptimization from
     // deferred code.
     for (intptr_t i = 0;
@@ -1136,8 +1137,9 @@
       __ orr(R0, ZR, Operand(R0));  // nop
     }
     lazy_deopt_pc_offset_ = assembler()->CodeSize();
-  __ BranchPatchable(*StubCode::DeoptimizeLazy_entry());
+    __ BranchPatchable(*StubCode::DeoptimizeLazy_entry());
   }
+  EndCodeSourceRange(TokenPosition::kDartCodeEpilogue);
 }
 
 
@@ -1172,6 +1174,34 @@
 }
 
 
+void FlowGraphCompiler::GenerateStaticDartCall(intptr_t deopt_id,
+                                               TokenPosition token_pos,
+                                               const StubEntry& stub_entry,
+                                               RawPcDescriptors::Kind kind,
+                                               LocationSummary* locs,
+                                               const Function& target) {
+  // Call sites to the same target can share object pool entries. These
+  // call sites are never patched for breakpoints: the function is deoptimized
+  // and the unoptimized code with IC calls for static calls is patched instead.
+  ASSERT(is_optimizing());
+  __ BranchLinkWithEquivalence(stub_entry, target);
+
+  AddCurrentDescriptor(kind, deopt_id, token_pos);
+  RecordSafepoint(locs);
+  // Marks either the continuation point in unoptimized code or the
+  // deoptimization point in optimized code, after call.
+  const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id);
+  if (is_optimizing()) {
+    AddDeoptIndexAtCall(deopt_id_after, token_pos);
+  } else {
+    // Add deoptimization continuation point after the call and before the
+    // arguments are removed.
+    AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos);
+  }
+  AddStaticCallTarget(target);
+}
+
+
 void FlowGraphCompiler::GenerateRuntimeCall(TokenPosition token_pos,
                                             intptr_t deopt_id,
                                             const RuntimeEntry& entry,
@@ -1280,7 +1310,7 @@
 
   RecordSafepoint(locs);
   const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id);
-  if (FLAG_precompilation) {
+  if (FLAG_precompiled_mode) {
     // Megamorphic calls may occur in slow path stubs.
     // If valid use try_index argument.
     if (try_index == CatchClauseNode::kInvalidTryIndex) {
@@ -1374,12 +1404,12 @@
   __ LoadObject(R4, arguments_descriptor);
   // Do not use the code from the function, but let the code be patched so that
   // we can record the outgoing edges to other code.
-  GenerateDartCall(deopt_id,
-                   token_pos,
-                   *StubCode::CallStaticFunction_entry(),
-                   RawPcDescriptors::kOther,
-                   locs);
-  AddStaticCallTarget(function);
+  GenerateStaticDartCall(deopt_id,
+                         token_pos,
+                         *StubCode::CallStaticFunction_entry(),
+                         RawPcDescriptors::kOther,
+                         locs,
+                         function);
   __ Drop(argument_count);
 }
 
@@ -1548,14 +1578,14 @@
     }
     // Do not use the code from the function, but let the code be patched so
     // that we can record the outgoing edges to other code.
-    GenerateDartCall(deopt_id,
-                     token_index,
-                     *StubCode::CallStaticFunction_entry(),
-                     RawPcDescriptors::kOther,
-                     locs);
     const Function& function = Function::ZoneHandle(
         zone(), ic_data.GetTargetAt(0));
-    AddStaticCallTarget(function);
+    GenerateStaticDartCall(deopt_id,
+                           token_index,
+                           *StubCode::CallStaticFunction_entry(),
+                           RawPcDescriptors::kOther,
+                           locs,
+                           function);
     __ Drop(argument_count);
     if (kNumChecks > 1) {
       __ b(match_found);
@@ -1590,13 +1620,13 @@
     }
     // Do not use the code from the function, but let the code be patched so
     // that we can record the outgoing edges to other code.
-    GenerateDartCall(deopt_id,
-                     token_index,
-                     *StubCode::CallStaticFunction_entry(),
-                     RawPcDescriptors::kOther,
-                     locs);
     const Function& function = *sorted[i].target;
-    AddStaticCallTarget(function);
+    GenerateStaticDartCall(deopt_id,
+                           token_index,
+                           *StubCode::CallStaticFunction_entry(),
+                           RawPcDescriptors::kOther,
+                           locs,
+                           function);
     __ Drop(argument_count);
     if (!kIsLastCheck) {
       __ b(match_found);
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index 3ae8998..2ede9e0 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -31,7 +31,6 @@
 
 DECLARE_FLAG(bool, enable_simd_inline);
 DECLARE_FLAG(bool, use_megamorphic_stub);
-DECLARE_FLAG(bool, precompilation);
 
 
 void MegamorphicSlowPath::EmitNativeCode(FlowGraphCompiler* compiler) {
@@ -1139,19 +1138,22 @@
     }
   }
 
+  EndCodeSourceRange(TokenPosition::kDartCodePrologue);
   ASSERT(!block_order().is_empty());
   VisitBlocks();
 
   __ int3();
   GenerateDeferredCode();
 
-  if (is_optimizing() && !FLAG_precompilation) {
+  BeginCodeSourceRange();
+  if (is_optimizing() && !FLAG_precompiled_mode) {
     // Leave enough space for patching in case of lazy deoptimization from
     // deferred code.
     __ nop(CallPattern::pattern_length_in_bytes());
     lazy_deopt_pc_offset_ = assembler()->CodeSize();
     __ Jmp(*StubCode::DeoptimizeLazy_entry());
   }
+  EndCodeSourceRange(TokenPosition::kDartCodeEpilogue);
 }
 
 
@@ -1311,7 +1313,7 @@
   RecordSafepoint(locs);
   const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id);
   // Precompilation not implemented on ia32 platform.
-  ASSERT(!FLAG_precompilation);
+  ASSERT(!FLAG_precompiled_mode);
   if (is_optimizing()) {
     AddDeoptIndexAtCall(deopt_id_after, token_pos);
   } else {
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index 273a0e0..8f51f86 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -24,7 +24,6 @@
 
 DEFINE_FLAG(bool, trap_on_deoptimization, false, "Trap on deoptimization.");
 DECLARE_FLAG(bool, use_megamorphic_stub);
-DECLARE_FLAG(bool, precompilation);
 
 
 void MegamorphicSlowPath::EmitNativeCode(FlowGraphCompiler* compiler) {
@@ -1142,12 +1141,14 @@
     }
   }
 
+  EndCodeSourceRange(TokenPosition::kDartCodePrologue);
   VisitBlocks();
 
   __ break_(0);
   GenerateDeferredCode();
 
-  if (is_optimizing() && !FLAG_precompilation) {
+  BeginCodeSourceRange();
+  if (is_optimizing() && !FLAG_precompiled_mode) {
     // Leave enough space for patching in case of lazy deoptimization from
     // deferred code.
     for (intptr_t i = 0;
@@ -1158,6 +1159,7 @@
     lazy_deopt_pc_offset_ = assembler()->CodeSize();
     __ Branch(*StubCode::DeoptimizeLazy_entry());
   }
+  EndCodeSourceRange(TokenPosition::kDartCodeEpilogue);
 }
 
 
@@ -1194,6 +1196,36 @@
 }
 
 
+void FlowGraphCompiler::GenerateStaticDartCall(intptr_t deopt_id,
+                                               TokenPosition token_pos,
+                                               const StubEntry& stub_entry,
+                                               RawPcDescriptors::Kind kind,
+                                               LocationSummary* locs,
+                                               const Function& target) {
+  // Call sites to the same target can share object pool entries. These
+  // call sites are never patched for breakpoints: the function is deoptimized
+  // and the unoptimized code with IC calls for static calls is patched instead.
+  ASSERT(is_optimizing());
+  __ BranchLinkWithEquivalence(stub_entry, target);
+
+  AddCurrentDescriptor(kind, deopt_id, token_pos);
+  RecordSafepoint(locs);
+  // Marks either the continuation point in unoptimized code or the
+  // deoptimization point in optimized code, after call.
+  const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id);
+  if (is_optimizing()) {
+    AddDeoptIndexAtCall(deopt_id_after, token_pos);
+  } else {
+    // Add deoptimization continuation point after the call and before the
+    // arguments are removed.
+    AddCurrentDescriptor(RawPcDescriptors::kDeopt,
+                         deopt_id_after,
+                         token_pos);
+  }
+  AddStaticCallTarget(target);
+}
+
+
 void FlowGraphCompiler::GenerateRuntimeCall(TokenPosition token_pos,
                                             intptr_t deopt_id,
                                             const RuntimeEntry& entry,
@@ -1305,7 +1337,7 @@
 
   RecordSafepoint(locs);
   const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id);
-  if (FLAG_precompilation) {
+  if (FLAG_precompiled_mode) {
     // Megamorphic calls may occur in slow path stubs.
     // If valid use try_index argument.
     if (try_index == CatchClauseNode::kInvalidTryIndex) {
@@ -1400,12 +1432,12 @@
   __ LoadObject(S4, arguments_descriptor);
   // Do not use the code from the function, but let the code be patched so that
   // we can record the outgoing edges to other code.
-  GenerateDartCall(deopt_id,
-                   token_pos,
-                   *StubCode::CallStaticFunction_entry(),
-                   RawPcDescriptors::kOther,
-                   locs);
-  AddStaticCallTarget(function);
+  GenerateStaticDartCall(deopt_id,
+                         token_pos,
+                         *StubCode::CallStaticFunction_entry(),
+                         RawPcDescriptors::kOther,
+                         locs,
+                         function);
   __ Drop(argument_count);
 }
 
@@ -1614,14 +1646,14 @@
     }
     // Do not use the code from the function, but let the code be patched so
     // that we can record the outgoing edges to other code.
-    GenerateDartCall(deopt_id,
-                     token_index,
-                     *StubCode::CallStaticFunction_entry(),
-                     RawPcDescriptors::kOther,
-                     locs);
     const Function& function = Function::ZoneHandle(
         zone(), ic_data.GetTargetAt(0));
-    AddStaticCallTarget(function);
+    GenerateStaticDartCall(deopt_id,
+                           token_index,
+                           *StubCode::CallStaticFunction_entry(),
+                           RawPcDescriptors::kOther,
+                           locs,
+                           function);
     __ Drop(argument_count);
     if (kNumChecks > 1) {
       __ b(match_found);
@@ -1655,13 +1687,13 @@
     }
     // Do not use the code from the function, but let the code be patched so
     // that we can record the outgoing edges to other code.
-    GenerateDartCall(deopt_id,
-                     token_index,
-                     *StubCode::CallStaticFunction_entry(),
-                     RawPcDescriptors::kOther,
-                     locs);
     const Function& function = *sorted[i].target;
-    AddStaticCallTarget(function);
+    GenerateStaticDartCall(deopt_id,
+                           token_index,
+                           *StubCode::CallStaticFunction_entry(),
+                           RawPcDescriptors::kOther,
+                           locs,
+                           function);
     __ Drop(argument_count);
     if (!kIsLastCheck) {
       __ b(match_found);
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index 49aeed8..800e1dc 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -27,7 +27,6 @@
 DEFINE_FLAG(bool, unbox_mints, true, "Optimize 64-bit integer arithmetic.");
 DECLARE_FLAG(bool, enable_simd_inline);
 DECLARE_FLAG(bool, use_megamorphic_stub);
-DECLARE_FLAG(bool, precompilation);
 
 void MegamorphicSlowPath::EmitNativeCode(FlowGraphCompiler* compiler) {
   Assembler* assembler = compiler->assembler();
@@ -1137,6 +1136,7 @@
     }
   }
 
+  EndCodeSourceRange(TokenPosition::kDartCodePrologue);
   ASSERT(!block_order().is_empty());
   VisitBlocks();
 
@@ -1146,13 +1146,15 @@
   // Emit function patching code. This will be swapped with the first 13 bytes
   // at entry point.
 
-  if (is_optimizing() && !FLAG_precompilation) {
+  BeginCodeSourceRange();
+  if (is_optimizing() && !FLAG_precompiled_mode) {
     // Leave enough space for patching in case of lazy deoptimization from
     // deferred code.
     __ nop(ShortCallPattern::pattern_length_in_bytes());
     lazy_deopt_pc_offset_ = assembler()->CodeSize();
     __ Jmp(*StubCode::DeoptimizeLazy_entry(), PP);
   }
+  EndCodeSourceRange(TokenPosition::kDartCodeEpilogue);
 }
 
 
@@ -1187,6 +1189,34 @@
 }
 
 
+void FlowGraphCompiler::GenerateStaticDartCall(intptr_t deopt_id,
+                                               TokenPosition token_pos,
+                                               const StubEntry& stub_entry,
+                                               RawPcDescriptors::Kind kind,
+                                               LocationSummary* locs,
+                                               const Function& target) {
+  // Call sites to the same target can share object pool entries. These
+  // call sites are never patched for breakpoints: the function is deoptimized
+  // and the unoptimized code with IC calls for static calls is patched instead.
+  ASSERT(is_optimizing());
+  __ CallWithEquivalence(stub_entry, target);
+
+  AddCurrentDescriptor(kind, deopt_id, token_pos);
+  RecordSafepoint(locs);
+  // Marks either the continuation point in unoptimized code or the
+  // deoptimization point in optimized code, after call.
+  const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id);
+  if (is_optimizing()) {
+    AddDeoptIndexAtCall(deopt_id_after, token_pos);
+  } else {
+    // Add deoptimization continuation point after the call and before the
+    // arguments are removed.
+    AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos);
+  }
+  AddStaticCallTarget(target);
+}
+
+
 void FlowGraphCompiler::GenerateRuntimeCall(TokenPosition token_pos,
                                             intptr_t deopt_id,
                                             const RuntimeEntry& entry,
@@ -1310,7 +1340,7 @@
 
   RecordSafepoint(locs);
   const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id);
-  if (FLAG_precompilation) {
+  if (FLAG_precompiled_mode) {
     // Megamorphic calls may occur in slow path stubs.
     // If valid use try_index argument.
     if (try_index == CatchClauseNode::kInvalidTryIndex) {
@@ -1386,12 +1416,12 @@
   __ LoadObject(R10, arguments_descriptor);
   // Do not use the code from the function, but let the code be patched so that
   // we can record the outgoing edges to other code.
-  GenerateDartCall(deopt_id,
-                   token_pos,
-                   *StubCode::CallStaticFunction_entry(),
-                   RawPcDescriptors::kOther,
-                   locs);
-  AddStaticCallTarget(function);
+  GenerateStaticDartCall(deopt_id,
+                         token_pos,
+                         *StubCode::CallStaticFunction_entry(),
+                         RawPcDescriptors::kOther,
+                         locs,
+                         function);
   __ Drop(argument_count, RCX);
 }
 
@@ -1531,14 +1561,14 @@
     }
     // Do not use the code from the function, but let the code be patched so
     // that we can record the outgoing edges to other code.
-    GenerateDartCall(deopt_id,
-                     token_index,
-                     *StubCode::CallStaticFunction_entry(),
-                     RawPcDescriptors::kOther,
-                     locs);
     const Function& function = Function::ZoneHandle(
         zone(), ic_data.GetTargetAt(0));
-    AddStaticCallTarget(function);
+    GenerateStaticDartCall(deopt_id,
+                           token_index,
+                           *StubCode::CallStaticFunction_entry(),
+                           RawPcDescriptors::kOther,
+                           locs,
+                           function);
     __ Drop(argument_count, RCX);
     if (kNumChecks > 1) {
       __ jmp(match_found);
@@ -1573,13 +1603,13 @@
     }
     // Do not use the code from the function, but let the code be patched so
     // that we can record the outgoing edges to other code.
-    GenerateDartCall(deopt_id,
-                     token_index,
-                     *StubCode::CallStaticFunction_entry(),
-                     RawPcDescriptors::kOther,
-                     locs);
     const Function& function = *sorted[i].target;
-    AddStaticCallTarget(function);
+    GenerateStaticDartCall(deopt_id,
+                           token_index,
+                           *StubCode::CallStaticFunction_entry(),
+                           RawPcDescriptors::kOther,
+                           locs,
+                           function);
     __ Drop(argument_count, RCX);
     if (!kIsLastCheck) {
       __ jmp(match_found);
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index 9956af3..95a1c9f 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -12,10 +12,10 @@
 #include "vm/flow_graph.h"
 #include "vm/flow_graph_builder.h"
 #include "vm/flow_graph_compiler.h"
-#include "vm/flow_graph_optimizer.h"
 #include "vm/flow_graph_type_propagator.h"
 #include "vm/il_printer.h"
 #include "vm/intrinsifier.h"
+#include "vm/jit_optimizer.h"
 #include "vm/longjump.h"
 #include "vm/object.h"
 #include "vm/object_store.h"
@@ -62,7 +62,6 @@
 
 DECLARE_FLAG(bool, compiler_stats);
 DECLARE_FLAG(int, max_deoptimization_counter_threshold);
-DECLARE_FLAG(bool, precompilation);
 DECLARE_FLAG(bool, print_flow_graph);
 DECLARE_FLAG(bool, print_flow_graph_optimized);
 DECLARE_FLAG(bool, verify_compiler);
@@ -632,7 +631,7 @@
 
     // Function has no type feedback. With precompilation we don't rely on
     // type feedback.
-    if (!FLAG_precompilation &&
+    if (!FLAG_precompiled_mode &&
         function.ic_data_array() == Object::null()) {
       TRACE_INLINING(THR_Print("     Bailout: not compiled yet\n"));
       PRINT_INLINING_TREE("Not compiled",
@@ -790,7 +789,7 @@
           CSTAT_TIMER_SCOPE(thread(), graphinliner_opt_timer);
           // TODO(fschneider): Improve suppression of speculative inlining.
           // Deopt-ids overlap between caller and callee.
-          if (FLAG_precompilation) {
+          if (FLAG_precompiled_mode) {
             AotOptimizer optimizer(callee_graph,
                                    inliner_->use_speculative_inlining_,
                                    inliner_->inlining_black_list_);
@@ -810,9 +809,7 @@
             optimizer.TryOptimizePatterns();
             DEBUG_ASSERT(callee_graph->VerifyUseLists());
           } else {
-            FlowGraphOptimizer optimizer(callee_graph,
-                                         inliner_->use_speculative_inlining_,
-                                         inliner_->inlining_black_list_);
+            JitOptimizer optimizer(callee_graph);
             optimizer.ApplyICData();
             DEBUG_ASSERT(callee_graph->VerifyUseLists());
 
@@ -906,6 +903,7 @@
 
         FlowGraphInliner::SetInliningId(callee_graph,
             inliner_->NextInlineId(callee_graph->function(),
+                                   call_data->call->token_pos(),
                                    call_data->caller_inlining_id_));
         TRACE_INLINING(THR_Print("     Success\n"));
         PRINT_INLINING_TREE(NULL,
@@ -932,7 +930,7 @@
     // Propagate a compile-time error. Only in precompilation do we attempt to
     // inline functions that have never been compiled before; when JITing we
     // should only see compile-time errors in unoptimized compilation.
-    ASSERT(FLAG_precompilation);
+    ASSERT(FLAG_precompiled_mode);
     Thread::Current()->long_jump_base()->Jump(1, error);
     UNREACHABLE();
     return false;
@@ -1827,11 +1825,13 @@
 FlowGraphInliner::FlowGraphInliner(
     FlowGraph* flow_graph,
     GrowableArray<const Function*>* inline_id_to_function,
+    GrowableArray<TokenPosition>* inline_id_to_token_pos,
     GrowableArray<intptr_t>* caller_inline_id,
     bool use_speculative_inlining,
     GrowableArray<intptr_t>* inlining_black_list)
     : flow_graph_(flow_graph),
       inline_id_to_function_(inline_id_to_function),
+      inline_id_to_token_pos_(inline_id_to_token_pos),
       caller_inline_id_(caller_inline_id),
       trace_inlining_(ShouldTraceInlining(flow_graph)),
       use_speculative_inlining_(use_speculative_inlining),
@@ -1952,9 +1952,15 @@
 
 
 intptr_t FlowGraphInliner::NextInlineId(const Function& function,
+                                        TokenPosition tp,
                                         intptr_t parent_id) {
   const intptr_t id = inline_id_to_function_->length();
+  // TODO(johnmccutchan): Do not allow IsNoSource once all nodes have proper
+  // source positions.
+  ASSERT(tp.IsReal() || tp.IsSynthetic() || tp.IsNoSource());
   inline_id_to_function_->Add(&function);
+  inline_id_to_token_pos_->Add(tp);
+  ASSERT(inline_id_to_token_pos_->length() == inline_id_to_function_->length());
   caller_inline_id_->Add(parent_id);
   return id;
 }
@@ -2231,7 +2237,7 @@
                                    call->GetBlock()->try_index());
   (*entry)->InheritDeoptTarget(Z, call);
   Instruction* cursor = *entry;
-  if (flow_graph->isolate()->flags().type_checks()) {
+  if (flow_graph->isolate()->type_checks()) {
     // Only type check for the value. A type check for the index is not
     // needed here because we insert a deoptimizing smi-check for the case
     // the index is not a smi.
diff --git a/runtime/vm/flow_graph_inliner.h b/runtime/vm/flow_graph_inliner.h
index c4d8ca2..ade98b5 100644
--- a/runtime/vm/flow_graph_inliner.h
+++ b/runtime/vm/flow_graph_inliner.h
@@ -21,6 +21,7 @@
  public:
   FlowGraphInliner(FlowGraph* flow_graph,
                    GrowableArray<const Function*>* inline_id_to_function,
+                   GrowableArray<TokenPosition>* inline_id_to_token_pos,
                    GrowableArray<intptr_t>* caller_inline_id,
                    bool use_speculative_inlining,
                    GrowableArray<intptr_t>* inlining_black_list);
@@ -35,7 +36,9 @@
   bool AlwaysInline(const Function& function);
 
   FlowGraph* flow_graph() const { return flow_graph_; }
-  intptr_t NextInlineId(const Function& function, intptr_t caller_id);
+  intptr_t NextInlineId(const Function& function,
+                        TokenPosition tp,
+                        intptr_t caller_id);
 
   bool trace_inlining() const { return trace_inlining_; }
 
@@ -54,6 +57,7 @@
 
   FlowGraph* flow_graph_;
   GrowableArray<const Function*>* inline_id_to_function_;
+  GrowableArray<TokenPosition>* inline_id_to_token_pos_;
   GrowableArray<intptr_t>* caller_inline_id_;
   const bool trace_inlining_;
   const bool use_speculative_inlining_;
diff --git a/runtime/vm/flow_graph_range_analysis.cc b/runtime/vm/flow_graph_range_analysis.cc
index f9840c6..18eaa36 100644
--- a/runtime/vm/flow_graph_range_analysis.cc
+++ b/runtime/vm/flow_graph_range_analysis.cc
@@ -14,7 +14,6 @@
 DEFINE_FLAG(bool, trace_range_analysis, false, "Trace range analysis progress");
 DEFINE_FLAG(bool, trace_integer_ir_selection, false,
     "Print integer IR selection optimization pass.");
-DECLARE_FLAG(bool, precompilation);
 DECLARE_FLAG(bool, trace_constant_propagation);
 
 // Quick access to the locally defined isolate() and zone() methods.
@@ -1534,7 +1533,7 @@
     // optimistic hoisting of checks possible)
     const bool try_generalization =
         function.allows_bounds_check_generalization() &&
-        !FLAG_precompilation;
+        !FLAG_precompiled_mode;
 
     BoundsCheckGeneralizer generalizer(this, flow_graph_);
 
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc
index 9807bcf..df32f54 100644
--- a/runtime/vm/flow_graph_type_propagator.cc
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -15,7 +15,6 @@
             "Trace flow graph type propagation");
 
 DECLARE_FLAG(bool, propagate_types);
-DECLARE_FLAG(bool, fields_may_be_reset);
 
 
 void FlowGraphTypePropagator::Propagate(FlowGraph* flow_graph) {
@@ -46,7 +45,7 @@
     types_.Add(NULL);
   }
 
-  if (Isolate::Current()->flags().type_checks()) {
+  if (Isolate::Current()->type_checks()) {
     asserts_ = new ZoneGrowableArray<AssertAssignableInstr*>(
         flow_graph->current_ssa_temp_index());
     for (intptr_t i = 0; i < flow_graph->current_ssa_temp_index(); i++) {
@@ -128,7 +127,7 @@
 
   const intptr_t rollback_point = rollback_.length();
 
-  if (Isolate::Current()->flags().type_checks()) {
+  if (Isolate::Current()->type_checks()) {
     StrengthenAsserts(block);
   }
 
@@ -891,7 +890,7 @@
     return CompileType::FromCid(result_cid_);
   }
 
-  if (Isolate::Current()->flags().type_checks()) {
+  if (Isolate::Current()->type_checks()) {
     // Void functions are known to return null, which is checked at the return
     // from the function.
     const AbstractType& result_type =
@@ -906,7 +905,7 @@
 
 
 CompileType LoadLocalInstr::ComputeType() const {
-  if (Isolate::Current()->flags().type_checks()) {
+  if (Isolate::Current()->type_checks()) {
     return CompileType::FromAbstractType(local().type());
   }
   return CompileType::Dynamic();
@@ -950,7 +949,7 @@
   intptr_t cid = kDynamicCid;
   AbstractType* abstract_type = NULL;
   const Field& field = this->StaticField();
-  if (Isolate::Current()->flags().type_checks()) {
+  if (Isolate::Current()->type_checks()) {
     cid = kIllegalCid;
     abstract_type = &AbstractType::ZoneHandle(field.type());
   }
@@ -1009,7 +1008,7 @@
   }
 
   const AbstractType* abstract_type = NULL;
-  if (Isolate::Current()->flags().type_checks() &&
+  if (Isolate::Current()->type_checks() &&
       type().HasResolvedTypeClass() &&
       !Field::IsExternalizableCid(Class::Handle(type().type_class()).id())) {
     abstract_type = &type();
diff --git a/runtime/vm/il_printer.cc b/runtime/vm/il_printer.cc
index 207167c..b3e48f1 100644
--- a/runtime/vm/il_printer.cc
+++ b/runtime/vm/il_printer.cc
@@ -171,7 +171,7 @@
   if ((cid_ != kIllegalCid) && (cid_ != kDynamicCid)) {
     const Class& cls =
         Class::Handle(Isolate::Current()->class_table()->At(cid_));
-    type_name = String::Handle(cls.PrettyName()).ToCString();
+    type_name = String::Handle(cls.ScrubbedName()).ToCString();
   } else if (type_ != NULL &&
              !type_->Equals(Type::Handle(Type::DynamicType()))) {
     type_name = type_->ToCString();
@@ -447,6 +447,9 @@
     PushArgumentAt(i)->value()->PrintTo(f);
   }
   PrintICDataHelper(f, ic_data());
+  if (with_checks()) {
+    f->Print(" WITH CHECKS");
+  }
 }
 
 
@@ -565,7 +568,7 @@
 
 
 void AllocateObjectInstr::PrintOperandsTo(BufferFormatter* f) const {
-  f->Print("%s", String::Handle(cls().PrettyName()).ToCString());
+  f->Print("%s", String::Handle(cls().ScrubbedName()).ToCString());
   for (intptr_t i = 0; i < ArgumentCount(); i++) {
     f->Print(", ");
     PushArgumentAt(i)->value()->PrintTo(f);
@@ -578,7 +581,7 @@
 
 
 void MaterializeObjectInstr::PrintOperandsTo(BufferFormatter* f) const {
-  f->Print("%s", String::Handle(cls_.PrettyName()).ToCString());
+  f->Print("%s", String::Handle(cls_.ScrubbedName()).ToCString());
   for (intptr_t i = 0; i < InputCount(); i++) {
     f->Print(", ");
     f->Print("%s: ", slots_[i]->ToCString());
@@ -926,7 +929,7 @@
 
   const Class& cls =
     Class::Handle(Isolate::Current()->class_table()->At(cid()));
-  f->Print(", %s", String::Handle(cls.PrettyName()).ToCString());
+  f->Print(", %s", String::Handle(cls.ScrubbedName()).ToCString());
 }
 
 
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index b2b4df6..4f4032f 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -13,7 +13,6 @@
 #include "vm/flow_graph_allocator.h"
 #include "vm/flow_graph_builder.h"
 #include "vm/flow_graph_compiler.h"
-#include "vm/flow_graph_optimizer.h"
 #include "vm/flow_graph_range_analysis.h"
 #include "vm/locations.h"
 #include "vm/method_recognizer.h"
@@ -30,19 +29,23 @@
 
 namespace dart {
 
-DEFINE_FLAG(bool, ic_range_profiling, true,
-    "Generate special IC stubs collecting range information "
-    "for binary and unary arithmetic operations");
 DEFINE_FLAG(bool, propagate_ic_data, true,
     "Propagate IC data from unoptimized to optimized IC calls.");
 DEFINE_FLAG(bool, two_args_smi_icd, true,
     "Generate special IC stubs for two args Smi operations");
 DEFINE_FLAG(bool, unbox_numeric_fields, true,
     "Support unboxed double and float32x4 fields.");
-DEFINE_FLAG(bool, fields_may_be_reset, false,
-            "Don't optimize away static field initialization");
 DECLARE_FLAG(bool, eliminate_type_checks);
 
+
+#if defined(DEBUG)
+void Instruction::CheckField(const Field& field) const {
+  ASSERT(field.IsZoneHandle());
+  ASSERT(!Compiler::IsBackgroundCompilation() || !field.IsOriginal());
+}
+#endif  // DEBUG
+
+
 Definition::Definition(intptr_t deopt_id)
     : Instruction(deopt_id),
       range_(NULL),
@@ -412,7 +415,7 @@
 
 
 const Field& LoadStaticFieldInstr::StaticField() const {
-  Field& field = Field::Handle();
+  Field& field = Field::ZoneHandle();
   field ^= field_value()->BoundConstant().raw();
   return field;
 }
@@ -425,6 +428,7 @@
   ASSERT(!value.IsBigint() || !Bigint::Cast(value).FitsIntoSmi());
   ASSERT(!value.IsBigint() || !Bigint::Cast(value).FitsIntoInt64());
   ASSERT(!value.IsMint() || !Smi::IsValid(Mint::Cast(value).AsInt64Value()));
+  ASSERT(!value.IsField() || Field::Cast(value).IsOriginal());
 }
 
 
@@ -2075,7 +2079,7 @@
 
 
 Definition* InstantiateTypeArgumentsInstr::Canonicalize(FlowGraph* flow_graph) {
-  return (Isolate::Current()->flags().type_checks() || HasUses()) ? this : NULL;
+  return (Isolate::Current()->type_checks() || HasUses()) ? this : NULL;
 }
 
 
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index 8677ac9..f424c99 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -714,6 +714,16 @@
 
   virtual const char* DebugName() const = 0;
 
+#if defined(DEBUG)
+  // Checks that the field stored in an instruction has proper form:
+  // - must be a zone-handle
+  // - In background compilation, must be cloned.
+  // Aborts if field is not OK.
+  void CheckField(const Field& field) const;
+#else
+  void CheckField(const Field& field) const {}
+#endif  // DEBUG
+
   // Printing support.
   const char* ToCString() const;
 #ifndef PRODUCT
@@ -2842,7 +2852,7 @@
   PRINT_OPERANDS_TO_SUPPORT
 
  protected:
-  friend class FlowGraphOptimizer;
+  friend class JitOptimizer;
   void set_ic_data(ICData* value) { ic_data_ = value; }
 
  private:
@@ -3550,6 +3560,7 @@
         is_object_reference_initialization_(false) {
     SetInputAt(kInstancePos, instance);
     SetInputAt(kValuePos, value);
+    CheckField(field);
   }
 
   StoreInstanceFieldInstr(intptr_t offset_in_bytes,
@@ -3620,7 +3631,7 @@
   PRINT_OPERANDS_TO_SUPPORT
 
  private:
-  friend class FlowGraphOptimizer;  // For ASSERT(initialization_).
+  friend class JitOptimizer;  // For ASSERT(initialization_).
 
   bool CanValueBeSmi() const {
     const intptr_t cid = value()->Type()->ToNullableCid();
@@ -3651,6 +3662,7 @@
     : TemplateInstruction(deopt_id),
       field_(field) {
     SetInputAt(0, value);
+    CheckField(field);
   }
 
   Value* value() const { return inputs_[0]; }
@@ -3677,7 +3689,9 @@
   GuardFieldClassInstr(Value* value,
                        const Field& field,
                        intptr_t deopt_id)
-    : GuardFieldInstr(value, field, deopt_id) { }
+      : GuardFieldInstr(value, field, deopt_id) {
+    CheckField(field);
+  }
 
   DECLARE_INSTRUCTION(GuardFieldClass)
 
@@ -3695,7 +3709,9 @@
   GuardFieldLengthInstr(Value* value,
                        const Field& field,
                        intptr_t deopt_id)
-    : GuardFieldInstr(value, field, deopt_id) { }
+      : GuardFieldInstr(value, field, deopt_id) {
+    CheckField(field);
+  }
 
   DECLARE_INSTRUCTION(GuardFieldLength)
 
@@ -3750,6 +3766,7 @@
         token_pos_(token_pos) {
     ASSERT(field.IsZoneHandle());
     SetInputAt(kValuePos, value);
+    CheckField(field);
   }
 
   enum {
@@ -4641,6 +4658,7 @@
       : TemplateInstruction(Thread::Current()->GetNextDeoptId()),
         field_(field) {
     SetInputAt(0, input);
+    CheckField(field);
   }
 
   virtual TokenPosition token_pos() const {
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index 93619bc..df31e31 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -22,15 +22,10 @@
 #include "vm/symbols.h"
 
 #define __ compiler->assembler()->
+#define Z (compiler->zone())
 
 namespace dart {
 
-DECLARE_FLAG(bool, allow_absolute_addresses);
-DECLARE_FLAG(bool, emit_edge_counters);
-DECLARE_FLAG(int, optimization_counter_threshold);
-DECLARE_FLAG(bool, precompilation);
-DECLARE_FLAG(bool, use_osr);
-
 // Generic summary for call instructions that have all arguments pushed
 // on the stack and return the result in a fixed register R0.
 LocationSummary* Instruction::MakeCallSummary(Zone* zone) {
@@ -379,13 +374,13 @@
   ASSERT(locs->always_calls());
   Label done;
 
-  if (Isolate::Current()->flags().type_checks()) {
+  if (Isolate::Current()->type_checks()) {
     __ CompareObject(reg, Bool::True());
     __ b(&done, EQ);
     __ CompareObject(reg, Bool::False());
     __ b(&done, EQ);
   } else {
-    ASSERT(Isolate::Current()->flags().asserts());
+    ASSERT(Isolate::Current()->asserts());
     __ CompareObject(reg, Object::null_instance());
     __ b(&done, NE);
   }
@@ -1616,7 +1611,7 @@
   Label* fail = (deopt != NULL) ? deopt : &fail_label;
 
   if (emit_full_guard) {
-    __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
+    __ LoadObject(field_reg, Field::ZoneHandle(field().Original()));
 
     FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset());
     FieldAddress field_nullability_operand(
@@ -1763,7 +1758,7 @@
 
     Label ok;
 
-    __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
+    __ LoadObject(field_reg, Field::ZoneHandle(field().Original()));
 
     __ ldrsb(offset_reg, FieldAddress(field_reg,
         Field::guarded_list_length_in_object_offset_offset()));
@@ -1823,7 +1818,7 @@
     if (Assembler::EmittingComments()) {
       __ Comment("%s slow path allocation of %s",
                  instruction_->DebugName(),
-                 String::Handle(cls_.PrettyName()).ToCString());
+                 String::Handle(cls_.ScrubbedName()).ToCString());
     }
     __ Bind(entry_label());
     const Code& stub = Code::ZoneHandle(
@@ -2120,7 +2115,7 @@
     Label store_float32x4;
     Label store_float64x2;
 
-    __ LoadObject(temp, Field::ZoneHandle(field().raw()));
+    __ LoadObject(temp, Field::ZoneHandle(Z, field().Original()));
 
     __ ldrh(temp2, FieldAddress(temp, Field::is_nullable_offset()));
     __ CompareImmediate(temp2, kNullCid);
@@ -2260,7 +2255,7 @@
   const Register value = locs()->in(0).reg();
   const Register temp = locs()->temp(0).reg();
 
-  __ LoadObject(temp, field());
+  __ LoadObject(temp, Field::ZoneHandle(Z, field().Original()));
   if (this->value()->NeedsStoreBuffer()) {
     __ StoreIntoObject(temp,
                        FieldAddress(temp, Field::static_value_offset()),
@@ -2378,7 +2373,7 @@
   ASSERT(locs()->in(kLengthPos).reg() == kLengthReg);
 
   if (compiler->is_optimizing() &&
-      !FLAG_precompilation &&
+      !FLAG_precompiled_mode &&
       num_elements()->BindsToConstant() &&
       num_elements()->BoundConstant().IsSmi()) {
     const intptr_t length = Smi::Cast(num_elements()->BoundConstant()).Value();
@@ -2482,7 +2477,7 @@
     Label load_float32x4;
     Label load_float64x2;
 
-    __ LoadObject(result_reg, Field::ZoneHandle(field()->raw()));
+    __ LoadObject(result_reg, Field::ZoneHandle(field()->Original()));
 
     FieldAddress field_cid_operand(result_reg, Field::guarded_cid_offset());
     FieldAddress field_nullability_operand(result_reg,
diff --git a/runtime/vm/intermediate_language_arm64.cc b/runtime/vm/intermediate_language_arm64.cc
index 0627f74..79296b3 100644
--- a/runtime/vm/intermediate_language_arm64.cc
+++ b/runtime/vm/intermediate_language_arm64.cc
@@ -21,15 +21,10 @@
 #include "vm/symbols.h"
 
 #define __ compiler->assembler()->
+#define Z (compiler->zone())
 
 namespace dart {
 
-DECLARE_FLAG(bool, allow_absolute_addresses);
-DECLARE_FLAG(bool, emit_edge_counters);
-DECLARE_FLAG(int, optimization_counter_threshold);
-DECLARE_FLAG(bool, precompilation);
-DECLARE_FLAG(bool, use_osr);
-
 // Generic summary for call instructions that have all arguments pushed
 // on the stack and return the result in a fixed register R0.
 LocationSummary* Instruction::MakeCallSummary(Zone* zone) {
@@ -367,13 +362,13 @@
   ASSERT(locs->always_calls());
   Label done;
 
-  if (Isolate::Current()->flags().type_checks()) {
+  if (Isolate::Current()->type_checks()) {
     __ CompareObject(reg, Bool::True());
     __ b(&done, EQ);
     __ CompareObject(reg, Bool::False());
     __ b(&done, EQ);
   } else {
-    ASSERT(Isolate::Current()->flags().asserts());
+    ASSERT(Isolate::Current()->asserts());
     __ CompareObject(reg, Object::null_instance());
     __ b(&done, NE);
   }
@@ -1473,7 +1468,7 @@
   Label* fail = (deopt != NULL) ? deopt : &fail_label;
 
   if (emit_full_guard) {
-    __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
+    __ LoadObject(field_reg, Field::ZoneHandle(field().Original()));
 
     FieldAddress field_cid_operand(
         field_reg, Field::guarded_cid_offset(), kUnsignedWord);
@@ -1617,7 +1612,7 @@
 
     Label ok;
 
-    __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
+    __ LoadObject(field_reg, Field::ZoneHandle(field().Original()));
 
     __ ldr(offset_reg,
            FieldAddress(field_reg,
@@ -1675,7 +1670,7 @@
     if (Assembler::EmittingComments()) {
       __ Comment("%s slow path allocation of %s",
                  instruction_->DebugName(),
-                 String::Handle(cls_.PrettyName()).ToCString());
+                 String::Handle(cls_.ScrubbedName()).ToCString());
     }
     __ Bind(entry_label());
     const Code& stub = Code::ZoneHandle(compiler->zone(),
@@ -1843,7 +1838,7 @@
     Label store_float32x4;
     Label store_float64x2;
 
-    __ LoadObject(temp, Field::ZoneHandle(field().raw()));
+    __ LoadObject(temp, Field::ZoneHandle(Z, field().Original()));
 
     __ LoadFieldFromOffset(temp2, temp, Field::is_nullable_offset(),
                            kUnsignedWord);
@@ -1981,7 +1976,7 @@
   const Register value = locs()->in(0).reg();
   const Register temp = locs()->temp(0).reg();
 
-  __ LoadObject(temp, field());
+  __ LoadObject(temp, Field::ZoneHandle(Z, field().Original()));
   if (this->value()->NeedsStoreBuffer()) {
     __ StoreIntoObjectOffset(
         temp, Field::static_value_offset(), value, CanValueBeSmi());
@@ -2101,7 +2096,7 @@
   ASSERT(locs()->in(kLengthPos).reg() == kLengthReg);
 
   if (compiler->is_optimizing() &&
-      !FLAG_precompilation &&
+      !FLAG_precompiled_mode &&
       num_elements()->BindsToConstant() &&
       num_elements()->BoundConstant().IsSmi()) {
     const intptr_t length = Smi::Cast(num_elements()->BoundConstant()).Value();
@@ -2193,7 +2188,7 @@
     Label load_float32x4;
     Label load_float64x2;
 
-    __ LoadObject(result_reg, Field::ZoneHandle(field()->raw()));
+    __ LoadObject(result_reg, Field::ZoneHandle(field()->Original()));
 
     FieldAddress field_cid_operand(
         result_reg, Field::guarded_cid_offset(), kUnsignedWord);
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index 8933848..bebb561 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -20,13 +20,10 @@
 #include "vm/symbols.h"
 
 #define __ compiler->assembler()->
+#define Z (compiler->zone())
 
 namespace dart {
 
-DECLARE_FLAG(bool, emit_edge_counters);
-DECLARE_FLAG(int, optimization_counter_threshold);
-DECLARE_FLAG(bool, use_osr);
-
 // Generic summary for call instructions that have all arguments pushed
 // on the stack and return the result in a fixed register EAX.
 LocationSummary* Instruction::MakeCallSummary(Zone* zone) {
@@ -251,13 +248,13 @@
   ASSERT(locs->always_calls());
   Label done;
 
-  if (Isolate::Current()->flags().type_checks()) {
+  if (Isolate::Current()->type_checks()) {
     __ CompareObject(reg, Bool::True());
     __ j(EQUAL, &done, Assembler::kNearJump);
     __ CompareObject(reg, Bool::False());
     __ j(EQUAL, &done, Assembler::kNearJump);
   } else {
-    ASSERT(Isolate::Current()->flags().asserts());
+    ASSERT(Isolate::Current()->asserts());
     __ CompareObject(reg, Object::null_instance());
     __ j(NOT_EQUAL, &done, Assembler::kNearJump);
   }
@@ -1445,7 +1442,7 @@
   Label* fail = (deopt != NULL) ? deopt : &fail_label;
 
   if (emit_full_guard) {
-    __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
+    __ LoadObject(field_reg, Field::ZoneHandle(field().Original()));
 
     FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset());
     FieldAddress field_nullability_operand(
@@ -1593,7 +1590,7 @@
 
     Label ok;
 
-    __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
+    __ LoadObject(field_reg, Field::ZoneHandle(field().Original()));
 
     __ movsxb(offset_reg, FieldAddress(field_reg,
         Field::guarded_list_length_in_object_offset_offset()));
@@ -1648,7 +1645,7 @@
     if (Assembler::EmittingComments()) {
       __ Comment("%s slow path allocation of %s",
                  instruction_->DebugName(),
-                 String::Handle(cls_.PrettyName()).ToCString());
+                 String::Handle(cls_.ScrubbedName()).ToCString());
     }
     __ Bind(entry_label());
     const Code& stub = Code::ZoneHandle(
@@ -1833,7 +1830,7 @@
     Label store_float32x4;
     Label store_float64x2;
 
-    __ LoadObject(temp, Field::ZoneHandle(field().raw()));
+    __ LoadObject(temp, Field::ZoneHandle(Z, field().Original()));
 
     __ cmpw(FieldAddress(temp, Field::is_nullable_offset()),
             Immediate(kNullCid));
@@ -1979,7 +1976,7 @@
   Register value = locs()->in(0).reg();
   Register temp = locs()->temp(0).reg();
 
-  __ LoadObject(temp, field());
+  __ LoadObject(temp, Field::ZoneHandle(Z, field().Original()));
   if (this->value()->NeedsStoreBuffer()) {
     __ StoreIntoObject(temp,
                        FieldAddress(temp, Field::static_value_offset()),
@@ -2202,7 +2199,7 @@
     Label load_float32x4;
     Label load_float64x2;
 
-    __ LoadObject(result, Field::ZoneHandle(field()->raw()));
+    __ LoadObject(result, Field::ZoneHandle(field()->Original()));
 
     FieldAddress field_cid_operand(result, Field::guarded_cid_offset());
     FieldAddress field_nullability_operand(result, Field::is_nullable_offset());
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index 93e720c..f4b8032 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -21,15 +21,10 @@
 #include "vm/symbols.h"
 
 #define __ compiler->assembler()->
+#define Z (compiler->zone())
 
 namespace dart {
 
-DECLARE_FLAG(bool, allow_absolute_addresses);
-DECLARE_FLAG(bool, emit_edge_counters);
-DECLARE_FLAG(int, optimization_counter_threshold);
-DECLARE_FLAG(bool, precompilation);
-DECLARE_FLAG(bool, use_osr);
-
 // Generic summary for call instructions that have all arguments pushed
 // on the stack and return the result in a fixed register V0.
 LocationSummary* Instruction::MakeCallSummary(Zone* zone) {
@@ -428,11 +423,11 @@
   ASSERT(locs->always_calls());
   Label done;
 
-  if (Isolate::Current()->flags().type_checks()) {
+  if (Isolate::Current()->type_checks()) {
     __ BranchEqual(reg, Bool::True(), &done);
     __ BranchEqual(reg, Bool::False(), &done);
   } else {
-    ASSERT(Isolate::Current()->flags().asserts());
+    ASSERT(Isolate::Current()->asserts());
     __ BranchNotEqual(reg, Object::null_instance(), &done);
   }
 
@@ -1647,7 +1642,7 @@
   Label* fail = (deopt != NULL) ? deopt : &fail_label;
 
   if (emit_full_guard) {
-    __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
+    __ LoadObject(field_reg, Field::ZoneHandle(field().Original()));
 
     FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset());
     FieldAddress field_nullability_operand(
@@ -1792,7 +1787,7 @@
 
     Label ok;
 
-    __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
+    __ LoadObject(field_reg, Field::ZoneHandle(field().Original()));
 
     __ lb(CMPRES1, FieldAddress(field_reg,
         Field::guarded_list_length_in_object_offset_offset()));
@@ -1849,7 +1844,7 @@
     if (Assembler::EmittingComments()) {
       __ Comment("%s slow path allocation of %s",
                  instruction_->DebugName(),
-                 String::Handle(cls_.PrettyName()).ToCString());
+                 String::Handle(cls_.ScrubbedName()).ToCString());
     }
     __ Bind(entry_label());
     const Code& stub = Code::ZoneHandle(
@@ -2007,7 +2002,7 @@
     Label store_pointer;
     Label store_double;
 
-    __ LoadObject(temp, Field::ZoneHandle(field().raw()));
+    __ LoadObject(temp, Field::ZoneHandle(Z, field().Original()));
 
     __ lhu(temp2, FieldAddress(temp, Field::is_nullable_offset()));
     __ BranchEqual(temp2, Immediate(kNullCid), &store_pointer);
@@ -2113,7 +2108,7 @@
   Register value = locs()->in(0).reg();
   Register temp = locs()->temp(0).reg();
 
-  __ LoadObject(temp, field());
+  __ LoadObject(temp, Field::ZoneHandle(Z, field().Original()));
   if (this->value()->NeedsStoreBuffer()) {
     __ StoreIntoObject(temp,
                        FieldAddress(temp, Field::static_value_offset()),
@@ -2232,7 +2227,7 @@
 
   Label slow_path, done;
   if (compiler->is_optimizing() &&
-      !FLAG_precompilation &&
+      !FLAG_precompiled_mode &&
       num_elements()->BindsToConstant() &&
       num_elements()->BoundConstant().IsSmi()) {
     const intptr_t length = Smi::Cast(num_elements()->BoundConstant()).Value();
@@ -2323,7 +2318,7 @@
     Label load_pointer;
     Label load_double;
 
-    __ LoadObject(result_reg, Field::ZoneHandle(field()->raw()));
+    __ LoadObject(result_reg, Field::ZoneHandle(field()->Original()));
 
     FieldAddress field_cid_operand(result_reg, Field::guarded_cid_offset());
     FieldAddress field_nullability_operand(result_reg,
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index 2fdf93e..ec108a8 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -20,15 +20,10 @@
 #include "vm/symbols.h"
 
 #define __ compiler->assembler()->
+#define Z (compiler->zone())
 
 namespace dart {
 
-DECLARE_FLAG(bool, allow_absolute_addresses);
-DECLARE_FLAG(bool, emit_edge_counters);
-DECLARE_FLAG(int, optimization_counter_threshold);
-DECLARE_FLAG(bool, use_osr);
-DECLARE_FLAG(bool, precompilation);
-
 // Generic summary for call instructions that have all arguments pushed
 // on the stack and return the result in a fixed register RAX.
 LocationSummary* Instruction::MakeCallSummary(Zone* zone) {
@@ -338,13 +333,13 @@
   ASSERT(locs->always_calls());
   Label done;
 
-  if (Isolate::Current()->flags().type_checks()) {
+  if (Isolate::Current()->type_checks()) {
     __ CompareObject(reg, Bool::True());
     __ j(EQUAL, &done, Assembler::kNearJump);
     __ CompareObject(reg, Bool::False());
     __ j(EQUAL, &done, Assembler::kNearJump);
   } else {
-    ASSERT(Isolate::Current()->flags().asserts());
+    ASSERT(Isolate::Current()->asserts());
     __ CompareObject(reg, Object::null_instance());
     __ j(NOT_EQUAL, &done, Assembler::kNearJump);
   }
@@ -1489,7 +1484,7 @@
   Label* fail = (deopt != NULL) ? deopt : &fail_label;
 
   if (emit_full_guard) {
-    __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
+    __ LoadObject(field_reg, Field::ZoneHandle(field().Original()));
 
     FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset());
     FieldAddress field_nullability_operand(
@@ -1623,7 +1618,7 @@
 
     Label ok;
 
-    __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
+    __ LoadObject(field_reg, Field::ZoneHandle(field().Original()));
 
     __ movsxb(offset_reg, FieldAddress(field_reg,
         Field::guarded_list_length_in_object_offset_offset()));
@@ -1679,7 +1674,7 @@
     if (Assembler::EmittingComments()) {
       __ Comment("%s slow path allocation of %s",
                  instruction_->DebugName(),
-                 String::Handle(cls_.PrettyName()).ToCString());
+                 String::Handle(cls_.ScrubbedName()).ToCString());
     }
     __ Bind(entry_label());
     const Code& stub = Code::ZoneHandle(compiler->zone(),
@@ -1861,7 +1856,7 @@
     Label store_float32x4;
     Label store_float64x2;
 
-    __ LoadObject(temp, Field::ZoneHandle(field().raw()));
+    __ LoadObject(temp, Field::ZoneHandle(Z, field().Original()));
 
     __ cmpl(FieldAddress(temp, Field::is_nullable_offset()),
             Immediate(kNullCid));
@@ -2003,7 +1998,7 @@
   Register value = locs()->in(0).reg();
   Register temp = locs()->temp(0).reg();
 
-  __ LoadObject(temp, field());
+  __ LoadObject(temp, Field::ZoneHandle(Z, field().Original()));
   if (this->value()->NeedsStoreBuffer()) {
     __ StoreIntoObject(temp,
                        FieldAddress(temp, Field::static_value_offset()),
@@ -2121,7 +2116,7 @@
 
   Label slow_path, done;
   if (compiler->is_optimizing() &&
-      !FLAG_precompilation &&
+      !FLAG_precompiled_mode &&
       num_elements()->BindsToConstant() &&
       num_elements()->BoundConstant().IsSmi()) {
     const intptr_t length = Smi::Cast(num_elements()->BoundConstant()).Value();
@@ -2221,7 +2216,7 @@
     Label load_float32x4;
     Label load_float64x2;
 
-    __ LoadObject(result, Field::ZoneHandle(field()->raw()));
+    __ LoadObject(result, Field::ZoneHandle(field()->Original()));
 
     __ cmpl(FieldAddress(result, Field::is_nullable_offset()),
             Immediate(kNullCid));
diff --git a/runtime/vm/intrinsifier.cc b/runtime/vm/intrinsifier.cc
index 193dba4..af15e7a 100644
--- a/runtime/vm/intrinsifier.cc
+++ b/runtime/vm/intrinsifier.cc
@@ -770,7 +770,7 @@
 
 
 bool Intrinsifier::Build_GrowableArraySetIndexed(FlowGraph* flow_graph) {
-  if (Isolate::Current()->flags().type_checks()) {
+  if (Isolate::Current()->type_checks()) {
     return false;
   }
 
diff --git a/runtime/vm/intrinsifier_arm.cc b/runtime/vm/intrinsifier_arm.cc
index 1b49169..0487fea 100644
--- a/runtime/vm/intrinsifier_arm.cc
+++ b/runtime/vm/intrinsifier_arm.cc
@@ -18,8 +18,6 @@
 
 namespace dart {
 
-DECLARE_FLAG(bool, interpret_irregexp);
-
 // When entering intrinsics code:
 // R4: Arguments descriptor
 // LR: Return address
@@ -37,7 +35,7 @@
 // Intrinsify only for Smi value and index. Non-smi values need a store buffer
 // update. Array length is always a Smi.
 void Intrinsifier::ObjectArraySetIndexed(Assembler* assembler) {
-  if (Isolate::Current()->flags().type_checks()) {
+  if (Isolate::Current()->type_checks()) {
     return;
   }
 
@@ -111,7 +109,7 @@
 // On stack: growable array (+1), value (+0).
 void Intrinsifier::GrowableArray_add(Assembler* assembler) {
   // In checked mode we need to type-check the incoming argument.
-  if (Isolate::Current()->flags().type_checks()) {
+  if (Isolate::Current()->type_checks()) {
     return;
   }
   Label fall_through;
diff --git a/runtime/vm/intrinsifier_arm64.cc b/runtime/vm/intrinsifier_arm64.cc
index 3c28ec1..f12ea8d 100644
--- a/runtime/vm/intrinsifier_arm64.cc
+++ b/runtime/vm/intrinsifier_arm64.cc
@@ -17,8 +17,6 @@
 
 namespace dart {
 
-DECLARE_FLAG(bool, interpret_irregexp);
-
 // When entering intrinsics code:
 // R4: Arguments descriptor
 // LR: Return address
@@ -36,7 +34,7 @@
 // Intrinsify only for Smi value and index. Non-smi values need a store buffer
 // update. Array length is always a Smi.
 void Intrinsifier::ObjectArraySetIndexed(Assembler* assembler) {
-  if (Isolate::Current()->flags().type_checks()) {
+  if (Isolate::Current()->type_checks()) {
     return;
   }
 
@@ -109,7 +107,7 @@
 // On stack: growable array (+1), value (+0).
 void Intrinsifier::GrowableArray_add(Assembler* assembler) {
   // In checked mode we need to type-check the incoming argument.
-  if (Isolate::Current()->flags().type_checks()) {
+  if (Isolate::Current()->type_checks()) {
     return;
   }
   Label fall_through;
diff --git a/runtime/vm/intrinsifier_ia32.cc b/runtime/vm/intrinsifier_ia32.cc
index 9f4c622..29870b2 100644
--- a/runtime/vm/intrinsifier_ia32.cc
+++ b/runtime/vm/intrinsifier_ia32.cc
@@ -24,8 +24,6 @@
 
 namespace dart {
 
-DECLARE_FLAG(bool, interpret_irregexp);
-
 // When entering intrinsics code:
 // ECX: IC Data
 // EDX: Arguments descriptor
@@ -57,7 +55,7 @@
 // update. Array length is always a Smi.
 void Intrinsifier::ObjectArraySetIndexed(Assembler* assembler) {
   Label fall_through;
-  if (Isolate::Current()->flags().type_checks()) {
+  if (Isolate::Current()->type_checks()) {
     const intptr_t type_args_field_offset =
         ComputeObjectArrayTypeArgumentsOffset();
     // Inline simple tests (Smi, null), fallthrough if not positive.
@@ -158,7 +156,7 @@
 // On stack: growable array (+2), value (+1), return-address (+0).
 void Intrinsifier::GrowableArray_add(Assembler* assembler) {
   // In checked mode we need to type-check the incoming argument.
-  if (Isolate::Current()->flags().type_checks()) return;
+  if (Isolate::Current()->type_checks()) return;
 
   Label fall_through;
   __ movl(EAX, Address(ESP, + 2 * kWordSize));  // Array.
diff --git a/runtime/vm/intrinsifier_mips.cc b/runtime/vm/intrinsifier_mips.cc
index 1e289cc..57cb4d6 100644
--- a/runtime/vm/intrinsifier_mips.cc
+++ b/runtime/vm/intrinsifier_mips.cc
@@ -17,8 +17,6 @@
 
 namespace dart {
 
-DECLARE_FLAG(bool, interpret_irregexp);
-
 // When entering intrinsics code:
 // S4: Arguments descriptor
 // RA: Return address
@@ -36,7 +34,7 @@
 // Intrinsify only for Smi value and index. Non-smi values need a store buffer
 // update. Array length is always a Smi.
 void Intrinsifier::ObjectArraySetIndexed(Assembler* assembler) {
-  if (Isolate::Current()->flags().type_checks()) {
+  if (Isolate::Current()->type_checks()) {
     return;
   }
 
@@ -108,7 +106,7 @@
 // On stack: growable array (+1), value (+0).
 void Intrinsifier::GrowableArray_add(Assembler* assembler) {
   // In checked mode we need to type-check the incoming argument.
-  if (Isolate::Current()->flags().type_checks()) return;
+  if (Isolate::Current()->type_checks()) return;
   Label fall_through;
   __ lw(T0, Address(SP, 1 * kWordSize));  // Array.
   __ lw(T1, FieldAddress(T0, GrowableObjectArray::length_offset()));
diff --git a/runtime/vm/intrinsifier_x64.cc b/runtime/vm/intrinsifier_x64.cc
index d9eb08b..e98777f 100644
--- a/runtime/vm/intrinsifier_x64.cc
+++ b/runtime/vm/intrinsifier_x64.cc
@@ -17,8 +17,6 @@
 
 namespace dart {
 
-DECLARE_FLAG(bool, interpret_irregexp);
-
 // When entering intrinsics code:
 // R10: Arguments descriptor
 // TOS: Return address
@@ -34,7 +32,7 @@
 
 
 void Intrinsifier::ObjectArraySetIndexed(Assembler* assembler) {
-  if (Isolate::Current()->flags().type_checks()) {
+  if (Isolate::Current()->type_checks()) {
     return;
   }
 
@@ -104,7 +102,7 @@
 // On stack: growable array (+2), value (+1), return-address (+0).
 void Intrinsifier::GrowableArray_add(Assembler* assembler) {
   // In checked mode we need to check the incoming argument.
-  if (Isolate::Current()->flags().type_checks()) return;
+  if (Isolate::Current()->type_checks()) return;
   Label fall_through;
   __ movq(RAX, Address(RSP, + 2 * kWordSize));  // Array.
   __ movq(RCX, FieldAddress(RAX, GrowableObjectArray::length_offset()));
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 3758c21..3fc7780 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -77,18 +77,9 @@
             "Max total size of external allocations in MB, or 0 for unlimited,"
             "e.g: --external_max_size=1024 allows up to 1024MB of externals");
 
-// TODO(iposva): Make these isolate specific flags inaccessible using the
-// regular FLAG_xyz pattern.
-// These flags are per-isolate and only influence the defaults.
-DEFINE_FLAG(bool, enable_asserts, false, "Enable assert statements.");
-DEFINE_FLAG(bool, enable_type_checks, false, "Enable type checks.");
-DEFINE_FLAG(bool, error_on_bad_override, false,
-            "Report error for bad overrides.");
-DEFINE_FLAG(bool, error_on_bad_type, false,
-            "Report error for malformed types.");
-
 DECLARE_FLAG(bool, warn_on_pause_with_no_debugger);
 
+NOT_IN_PRODUCT(
 static void CheckedModeHandler(bool value) {
   FLAG_enable_asserts = value;
   FLAG_enable_type_checks = value;
@@ -103,6 +94,7 @@
 DEFINE_FLAG_HANDLER(CheckedModeHandler,
                     checked,
                     "Enable checked mode.");
+)
 
 
 // Quick access to the locally defined thread() and isolate() methods.
@@ -655,20 +647,6 @@
 
 MessageHandler::MessageStatus IsolateMessageHandler::ProcessUnhandledException(
     const Error& result) {
-  // Notify the debugger about specific unhandled exceptions which are withheld
-  // when being thrown.
-  if (result.IsUnhandledException()) {
-    const UnhandledException& error = UnhandledException::Cast(result);
-    RawInstance* exception = error.exception();
-    if ((exception == I->object_store()->out_of_memory()) ||
-        (exception == I->object_store()->stack_overflow())) {
-      // We didn't notify the debugger when the stack was full. Do it now.
-      if (FLAG_support_debugger) {
-        I->debugger()->SignalExceptionThrown(Instance::Handle(exception));
-      }
-    }
-  }
-
   // Generate the error and stacktrace strings for the error message.
   String& exc_str = String::Handle(T->zone());
   String& stacktrace_str = String::Handle(T->zone());
@@ -704,6 +682,21 @@
       } else {
         T->set_sticky_error(result);
       }
+      // Notify the debugger about specific unhandled exceptions which are
+      // withheld when being thrown. Do this after setting the sticky error
+      // so the isolate has an error set when paused with the unhandled
+      // exception.
+      if (result.IsUnhandledException()) {
+        const UnhandledException& error = UnhandledException::Cast(result);
+        RawInstance* exception = error.exception();
+        if ((exception == I->object_store()->out_of_memory()) ||
+            (exception == I->object_store()->stack_overflow())) {
+          // We didn't notify the debugger when the stack was full. Do it now.
+          if (FLAG_support_debugger) {
+            I->debugger()->SignalExceptionThrown(Instance::Handle(exception));
+          }
+        }
+      }
       return kError;
     }
   }
@@ -711,31 +704,16 @@
 }
 
 
-Isolate::Flags::Flags()
-  : type_checks_(FLAG_enable_type_checks),
-    asserts_(FLAG_enable_asserts),
-    error_on_bad_type_(FLAG_error_on_bad_type),
-    error_on_bad_override_(FLAG_error_on_bad_override) {}
-
-
-void Isolate::Flags::CopyFrom(const Flags& orig) {
-  type_checks_ = orig.type_checks();
-  asserts_ = orig.asserts();
-  error_on_bad_type_ = orig.error_on_bad_type();
-  error_on_bad_override_ = orig.error_on_bad_override();
+void Isolate::FlagsInitialize(Dart_IsolateFlags* api_flags) {
+  api_flags->version = DART_FLAGS_CURRENT_VERSION;
+  api_flags->enable_type_checks = FLAG_enable_type_checks;
+  api_flags->enable_asserts = FLAG_enable_asserts;
+  api_flags->enable_error_on_bad_type = FLAG_error_on_bad_type;
+  api_flags->enable_error_on_bad_override = FLAG_error_on_bad_override;
 }
 
 
-void Isolate::Flags::CopyFrom(const Dart_IsolateFlags& api_flags) {
-  type_checks_ = api_flags.enable_type_checks;
-  asserts_ = api_flags.enable_asserts;
-  error_on_bad_type_ = api_flags.enable_error_on_bad_type;
-  error_on_bad_override_ = api_flags.enable_error_on_bad_override;
-  // Leave others at defaults.
-}
-
-
-void Isolate::Flags::CopyTo(Dart_IsolateFlags* api_flags) const {
+void Isolate::FlagsCopyTo(Dart_IsolateFlags* api_flags) const {
   api_flags->version = DART_FLAGS_CURRENT_VERSION;
   api_flags->enable_type_checks = type_checks();
   api_flags->enable_asserts = asserts();
@@ -744,7 +722,17 @@
 }
 
 
-#if defined(DEBUG)
+NOT_IN_PRODUCT(
+void Isolate::FlagsCopyFrom(const Dart_IsolateFlags& api_flags) {
+  type_checks_ = api_flags.enable_type_checks;
+  asserts_ = api_flags.enable_asserts;
+  error_on_bad_type_ = api_flags.enable_error_on_bad_type;
+  error_on_bad_override_ = api_flags.enable_error_on_bad_override;
+  // Leave others at defaults.
+})
+
+
+DEBUG_ONLY(
 // static
 void BaseIsolate::AssertCurrent(BaseIsolate* isolate) {
   ASSERT(isolate == Isolate::Current());
@@ -754,7 +742,7 @@
   ASSERT(Isolate::Current() == this);
   ASSERT(Thread::Current()->IsMutatorThread());
 }
-#endif  // defined(DEBUG)
+)
 
 #if defined(DEBUG)
 #define REUSABLE_HANDLE_SCOPE_INIT(object)                                     \
@@ -798,11 +786,11 @@
       resume_request_(false),
       last_resume_timestamp_(OS::GetCurrentTimeMillis()),
       has_compiled_code_(false),
-      flags_(),
       random_(),
       simulator_(NULL),
       mutex_(new Mutex()),
       symbols_mutex_(new Mutex()),
+      type_canonicalization_mutex_(new Mutex()),
       saved_stack_limit_(0),
       deferred_interrupts_mask_(0),
       deferred_interrupts_(0),
@@ -835,11 +823,11 @@
       cha_invalidation_gen_(kInvalidGen),
       field_invalidation_gen_(kInvalidGen),
       prefix_invalidation_gen_(kInvalidGen),
-      boxed_field_list_monitor_(new Monitor()),
+      boxed_field_list_mutex_(new Mutex()),
       boxed_field_list_(GrowableObjectArray::null()),
       spawn_count_monitor_(new Monitor()),
       spawn_count_(0) {
-  flags_.CopyFrom(api_flags);
+  NOT_IN_PRODUCT(FlagsCopyFrom(api_flags));
   // TODO(asiva): A Thread is not available here, need to figure out
   // how the vm_tag (kEmbedderTagId) can be set, these tags need to
   // move to the OSThread structure.
@@ -866,6 +854,8 @@
   mutex_ = NULL;  // Fail fast if interrupts are scheduled on a dead isolate.
   delete symbols_mutex_;
   symbols_mutex_ = NULL;
+  delete type_canonicalization_mutex_;
+  type_canonicalization_mutex_ = NULL;
   delete message_handler_;
   message_handler_ = NULL;  // Fail fast if we send messages to a dead isolate.
   ASSERT(deopt_context_ == NULL);  // No deopt in progress when isolate deleted.
@@ -876,8 +866,8 @@
   object_id_ring_ = NULL;
   delete pause_loop_monitor_;
   pause_loop_monitor_ = NULL;
-  delete boxed_field_list_monitor_;
-  boxed_field_list_monitor_ = NULL;
+  delete boxed_field_list_mutex_;
+  boxed_field_list_mutex_ = NULL;
   ASSERT(spawn_count_ == 0);
   delete spawn_count_monitor_;
   if (compiler_stats_ != NULL) {
@@ -1882,7 +1872,7 @@
   // Visit the boxed_field_list.
   // 'boxed_field_list_' access via mutator and background compilation threads
   // is guarded with a monitor. This means that we can visit it only
-  // when at safepoint or the boxed_field_list_monitor_ lock has been taken.
+  // when at safepoint or the boxed_field_list_mutex_ lock has been taken.
   visitor->VisitPointer(reinterpret_cast<RawObject**>(&boxed_field_list_));
 
   // Visit objects in the debugger.
@@ -2095,7 +2085,10 @@
 
 
 void Isolate::AddDeoptimizingBoxedField(const Field& field) {
-  MonitorLocker ml(boxed_field_list_monitor_);
+  ASSERT(field.IsOriginal());
+  // The enclosed code allocates objects and can potentially trigger a GC,
+  // ensure that we account for safepoints when grabbing the lock.
+  SafepointMutexLocker ml(boxed_field_list_mutex_);
   if (boxed_field_list_ == GrowableObjectArray::null()) {
     boxed_field_list_ = GrowableObjectArray::New(Heap::kOld);
   }
@@ -2106,7 +2099,7 @@
 
 
 RawField* Isolate::GetDeoptimizingBoxedField() {
-  MonitorLocker ml(boxed_field_list_monitor_);
+  MutexLocker ml(boxed_field_list_mutex_);
   if (boxed_field_list_ == GrowableObjectArray::null()) {
     return Field::null();
   }
@@ -2329,9 +2322,9 @@
     // Handle all available vm service messages, up to a resume
     // request.
     while (!resume && Dart_HasServiceMessages()) {
-      pause_loop_monitor_->Exit();
+      ml.Exit();
       resume = Dart_HandleServiceMessages();
-      pause_loop_monitor_->Enter();
+      ml.Enter();
     }
     if (resume) {
       break;
@@ -2350,7 +2343,9 @@
   if (visitor == NULL) {
     return;
   }
-  MonitorLocker ml(isolates_list_monitor_);
+  // The visitor could potentially run code that could safepoint so use
+  // SafepointMonitorLocker to ensure the lock has safepoint checks.
+  SafepointMonitorLocker ml(isolates_list_monitor_);
   Isolate* current = isolates_list_head_;
   while (current) {
     visitor->VisitIsolate(current);
@@ -2540,7 +2535,12 @@
   Thread* thread = NULL;
   OSThread* os_thread = OSThread::Current();
   if (os_thread != NULL) {
-    MonitorLocker ml(threads_lock());
+    // We are about to associate the thread with an isolate and it would
+    // not be possible to correctly track no_safepoint_scope_depth for the
+    // thread in the constructor/destructor of MonitorLocker,
+    // so we create a MonitorLocker object which does not do any
+    // no_safepoint_scope_depth increments/decrements.
+    MonitorLocker ml(threads_lock(), false);
 
     // If a safepoint operation is in progress wait for it
     // to finish before scheduling this thread in.
@@ -2560,6 +2560,7 @@
     ASSERT(thread->execution_state() == Thread::kThreadInVM);
     thread->set_safepoint_state(0);
     thread->set_vm_tag(VMTag::kVMTagId);
+    ASSERT(thread->no_safepoint_scope_depth() == 0);
     os_thread->set_thread(thread);
     if (is_mutator) {
       mutator_thread_ = thread;
@@ -2576,7 +2577,12 @@
                                bool bypass_safepoint) {
   // Disassociate the 'Thread' structure and unschedule the thread
   // from this isolate.
-  MonitorLocker ml(threads_lock());
+  // We are disassociating the thread from an isolate and it would
+  // not be possible to correctly track no_safepoint_scope_depth for the
+  // thread in the constructor/destructor of MonitorLocker,
+  // so we create a MonitorLocker object which does not do any
+  // no_safepoint_scope_depth increments/decrements.
+  MonitorLocker ml(threads_lock(), false);
   if (!bypass_safepoint) {
     // Ensure that the thread reports itself as being at a safepoint.
     thread->EnterSafepoint();
@@ -2594,6 +2600,7 @@
   thread->set_os_thread(NULL);
   thread->set_execution_state(Thread::kThreadInVM);
   thread->set_safepoint_state(0);
+  ASSERT(thread->no_safepoint_scope_depth() == 0);
   // Return thread structure.
   thread_registry()->ReturnThreadLocked(is_mutator, thread);
 }
@@ -2655,7 +2662,6 @@
       serialized_message_len_(0),
       spawn_count_monitor_(spawn_count_monitor),
       spawn_count_(spawn_count),
-      isolate_flags_(),
       paused_(paused),
       errors_are_fatal_(errors_are_fatal) {
   const Class& cls = Class::Handle(func.Owner());
@@ -2675,7 +2681,7 @@
                   &serialized_message_len_,
                   can_send_any_object);
   // Inherit flags from spawning isolate.
-  isolate_flags()->CopyFrom(Isolate::Current()->flags());
+  Isolate::Current()->FlagsCopyTo(isolate_flags());
 }
 
 
@@ -2725,7 +2731,7 @@
                   can_send_any_object);
   // By default inherit flags from spawning isolate. These can be overridden
   // from the calling code.
-  isolate_flags()->CopyFrom(Isolate::Current()->flags());
+  Isolate::Current()->FlagsCopyTo(isolate_flags());
 }
 
 
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index e9c255b..9d6aa28 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -319,6 +319,9 @@
 
   Mutex* mutex() const { return mutex_; }
   Mutex* symbols_mutex() const { return symbols_mutex_; }
+  Mutex* type_canonicalization_mutex() const {
+    return type_canonicalization_mutex_;
+  }
 
   Debugger* debugger() const {
     if (!FLAG_support_debugger) {
@@ -337,42 +340,6 @@
   void set_has_compiled_code(bool value) { has_compiled_code_ = value; }
   bool has_compiled_code() const { return has_compiled_code_; }
 
-  // TODO(iposva): Evaluate whether two different isolate flag structures are
-  // needed. Currently it serves as a separation between publicly visible flags
-  // and VM internal flags.
-  class Flags : public ValueObject {
-   public:
-    // Construct default flags as specified by the options.
-    Flags();
-
-    bool type_checks() const { return type_checks_; }
-    bool asserts() const { return asserts_; }
-    bool error_on_bad_type() const { return error_on_bad_type_; }
-    bool error_on_bad_override() const { return error_on_bad_override_; }
-
-    void set_checked(bool val) {
-      type_checks_ = val;
-      asserts_ = val;
-    }
-
-    void CopyFrom(const Flags& orig);
-    void CopyFrom(const Dart_IsolateFlags& api_flags);
-    void CopyTo(Dart_IsolateFlags* api_flags) const;
-
-   private:
-    bool type_checks_;
-    bool asserts_;
-    bool error_on_bad_type_;
-    bool error_on_bad_override_;
-
-    friend class Isolate;
-
-    DISALLOW_ALLOCATION();
-    DISALLOW_COPY_AND_ASSIGN(Flags);
-  };
-
-  const Flags& flags() const { return flags_; }
-
   // Lets the embedder know that a service message resulted in a resume request.
   void SetResumeRequest() {
     resume_request_ = true;
@@ -672,6 +639,23 @@
 
   bool is_service_isolate() const { return is_service_isolate_; }
 
+  // Isolate-specific flag handling.
+  static void FlagsInitialize(Dart_IsolateFlags* api_flags);
+  void FlagsCopyTo(Dart_IsolateFlags* api_flags) const;
+  void FlagsCopyFrom(const Dart_IsolateFlags& api_flags);
+
+#if defined(PRODUCT)
+  bool type_checks() const { return FLAG_enable_type_checks; }
+  bool asserts() const { return FLAG_enable_asserts; }
+  bool error_on_bad_type() const { return FLAG_error_on_bad_type; }
+  bool error_on_bad_override() const { return FLAG_error_on_bad_override; }
+#else  // defined(PRODUCT)
+  bool type_checks() const { return type_checks_; }
+  bool asserts() const { return asserts_; }
+  bool error_on_bad_type() const { return error_on_bad_type_; }
+  bool error_on_bad_override() const { return error_on_bad_override_; }
+#endif  // defined(PRODUCT)
+
   static void KillAllIsolates(LibMsgId msg_id);
   static void KillIfExists(Isolate* isolate, LibMsgId msg_id);
 
@@ -769,11 +753,11 @@
   bool resume_request_;
   int64_t last_resume_timestamp_;
   bool has_compiled_code_;  // Can check that no compilation occured.
-  Flags flags_;
   Random random_;
   Simulator* simulator_;
-  Mutex* mutex_;  // protects stack_limit_, saved_stack_limit_, compiler stats.
-  Mutex* symbols_mutex_;  // Protects concurrent access to teh symbol table.
+  Mutex* mutex_;  // Protects stack_limit_, saved_stack_limit_, compiler stats.
+  Mutex* symbols_mutex_;  // Protects concurrent access to the symbol table.
+  Mutex* type_canonicalization_mutex_;  // Protects type canonicalization.
   uword saved_stack_limit_;
   uword deferred_interrupts_mask_;
   uword deferred_interrupts_;
@@ -791,6 +775,14 @@
 
   bool is_service_isolate_;
 
+  // Isolate-specific flags.
+  NOT_IN_PRODUCT(
+    bool type_checks_;
+    bool asserts_;
+    bool error_on_bad_type_;
+    bool error_on_bad_override_;
+  )
+
   // Status support.
   char* stacktrace_;
   intptr_t stack_frame_index_;
@@ -849,7 +841,7 @@
   uint32_t prefix_invalidation_gen_;
 
   // Protect access to boxed_field_list_.
-  Monitor* boxed_field_list_monitor_;
+  Mutex* boxed_field_list_mutex_;
   // List of fields that became boxed and that trigger deoptimization.
   RawGrowableObjectArray* boxed_field_list_;
 
@@ -997,7 +989,7 @@
   bool is_spawn_uri() const { return library_url_ == NULL; }
   bool paused() const { return paused_; }
   bool errors_are_fatal() const { return errors_are_fatal_; }
-  Isolate::Flags* isolate_flags() { return &isolate_flags_; }
+  Dart_IsolateFlags* isolate_flags() { return &isolate_flags_; }
 
   RawObject* ResolveFunction();
   RawInstance* BuildArgs(Thread* thread);
@@ -1028,7 +1020,7 @@
   Monitor* spawn_count_monitor_;
   intptr_t* spawn_count_;
 
-  Isolate::Flags isolate_flags_;
+  Dart_IsolateFlags isolate_flags_;
   bool paused_;
   bool errors_are_fatal_;
 };
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/jit_optimizer.cc
similarity index 90%
rename from runtime/vm/flow_graph_optimizer.cc
rename to runtime/vm/jit_optimizer.cc
index fa5649f..f5f2211 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/jit_optimizer.cc
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-#include "vm/flow_graph_optimizer.h"
+#include "vm/jit_optimizer.h"
 
 #include "vm/bit_vector.h"
 #include "vm/branch_optimizer.h"
@@ -47,7 +47,7 @@
 
 
 // Optimize instance calls using ICData.
-void FlowGraphOptimizer::ApplyICData() {
+void JitOptimizer::ApplyICData() {
   VisitBlocks();
 }
 
@@ -58,7 +58,7 @@
 // have no runtime type feedback collected.
 // Attempts to convert an instance call (IC call) using propagated class-ids,
 // e.g., receiver class id, guarded-cid, or by guessing cid-s.
-void FlowGraphOptimizer::ApplyClassIds() {
+void JitOptimizer::ApplyClassIds() {
   ASSERT(current_iterator_ == NULL);
   for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
        !block_it.Done();
@@ -89,7 +89,7 @@
 }
 
 
-bool FlowGraphOptimizer::TryCreateICData(InstanceCallInstr* call) {
+bool JitOptimizer::TryCreateICData(InstanceCallInstr* call) {
   ASSERT(call->HasICData());
   if (call->ic_data()->NumberOfUsedChecks() > 0) {
     // This occurs when an instance call has too many checks, will be converted
@@ -198,8 +198,8 @@
 }
 
 
-const ICData& FlowGraphOptimizer::TrySpecializeICData(const ICData& ic_data,
-                                                      intptr_t cid) {
+const ICData& JitOptimizer::TrySpecializeICData(const ICData& ic_data,
+                                                intptr_t cid) {
   ASSERT(ic_data.NumArgsTested() == 1);
 
   if ((ic_data.NumberOfUsedChecks() == 1) && ic_data.HasReceiverClassId(cid)) {
@@ -226,7 +226,7 @@
 }
 
 
-void FlowGraphOptimizer::SpecializePolymorphicInstanceCall(
+void JitOptimizer::SpecializePolymorphicInstanceCall(
     PolymorphicInstanceCallInstr* call) {
   if (!FLAG_polymorphic_with_deopt) {
     // Specialization adds receiver checks which can lead to deoptimization.
@@ -275,7 +275,7 @@
 }
 
 
-void FlowGraphOptimizer::OptimizeLeftShiftBitAndSmiOp(
+void JitOptimizer::OptimizeLeftShiftBitAndSmiOp(
     Definition* bit_and_instr,
     Definition* left_instr,
     Definition* right_instr) {
@@ -313,10 +313,10 @@
 }
 
 
-void FlowGraphOptimizer::AppendExtractNthOutputForMerged(Definition* instr,
-                                                         intptr_t index,
-                                                         Representation rep,
-                                                         intptr_t cid) {
+void JitOptimizer::AppendExtractNthOutputForMerged(Definition* instr,
+                                                   intptr_t index,
+                                                   Representation rep,
+                                                   intptr_t cid) {
   ExtractNthOutputInstr* extract =
       new(Z) ExtractNthOutputInstr(new(Z) Value(instr), index, rep, cid);
   instr->ReplaceUsesWith(extract);
@@ -341,7 +341,7 @@
 //  v7 <- +(v5, v6)
 // Because of the environment it is important that merged instruction replaces
 // first original instruction encountered.
-void FlowGraphOptimizer::TryMergeTruncDivMod(
+void JitOptimizer::TryMergeTruncDivMod(
     GrowableArray<BinarySmiOpInstr*>* merge_candidates) {
   if (merge_candidates->length() < 2) {
     // Need at least a TRUNCDIV and a MOD.
@@ -402,7 +402,7 @@
 
 
 // Tries to merge MathUnary operations, in this case sinus and cosinus.
-void FlowGraphOptimizer::TryMergeMathUnary(
+void JitOptimizer::TryMergeMathUnary(
     GrowableArray<MathUnaryInstr*>* merge_candidates) {
   if (!FlowGraphCompiler::SupportsSinCos() || !CanUnboxDouble() ||
       !FLAG_merge_sin_cos) {
@@ -463,7 +463,7 @@
 // Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the
 // shift can be a truncating Smi shift-left and result is always Smi.
 // Merging occurs only per basic-block.
-void FlowGraphOptimizer::TryOptimizePatterns() {
+void JitOptimizer::TryOptimizePatterns() {
   if (!FLAG_truncating_left_shift) return;
   ASSERT(current_iterator_ == NULL);
   GrowableArray<BinarySmiOpInstr*> div_mod_merge;
@@ -649,8 +649,8 @@
 }
 
 
-void FlowGraphOptimizer::ReplaceCall(Definition* call,
-                                     Definition* replacement) {
+void JitOptimizer::ReplaceCall(Definition* call,
+                               Definition* replacement) {
   // Remove the original push arguments.
   for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
     PushArgumentInstr* push = call->PushArgumentAt(i);
@@ -661,10 +661,10 @@
 }
 
 
-void FlowGraphOptimizer::AddCheckSmi(Definition* to_check,
-                                     intptr_t deopt_id,
-                                     Environment* deopt_environment,
-                                     Instruction* insert_before) {
+void JitOptimizer::AddCheckSmi(Definition* to_check,
+                               intptr_t deopt_id,
+                               Environment* deopt_environment,
+                               Instruction* insert_before) {
   if (to_check->Type()->ToCid() != kSmiCid) {
     InsertBefore(insert_before,
                  new(Z) CheckSmiInstr(new(Z) Value(to_check),
@@ -676,10 +676,10 @@
 }
 
 
-Instruction* FlowGraphOptimizer::GetCheckClass(Definition* to_check,
-                                               const ICData& unary_checks,
-                                               intptr_t deopt_id,
-                                               TokenPosition token_pos) {
+Instruction* JitOptimizer::GetCheckClass(Definition* to_check,
+                                         const ICData& unary_checks,
+                                         intptr_t deopt_id,
+                                         TokenPosition token_pos) {
   if ((unary_checks.NumberOfUsedChecks() == 1) &&
       unary_checks.HasReceiverClassId(kSmiCid)) {
     return new(Z) CheckSmiInstr(new(Z) Value(to_check),
@@ -691,11 +691,11 @@
 }
 
 
-void FlowGraphOptimizer::AddCheckClass(Definition* to_check,
-                                       const ICData& unary_checks,
-                                       intptr_t deopt_id,
-                                       Environment* deopt_environment,
-                                       Instruction* insert_before) {
+void JitOptimizer::AddCheckClass(Definition* to_check,
+                                 const ICData& unary_checks,
+                                 intptr_t deopt_id,
+                                 Environment* deopt_environment,
+                                 Instruction* insert_before) {
   // Type propagation has not run yet, we cannot eliminate the check.
   Instruction* check = GetCheckClass(
       to_check, unary_checks, deopt_id, insert_before->token_pos());
@@ -703,7 +703,7 @@
 }
 
 
-void FlowGraphOptimizer::AddReceiverCheck(InstanceCallInstr* call) {
+void JitOptimizer::AddReceiverCheck(InstanceCallInstr* call) {
   AddCheckClass(call->ArgumentAt(0),
                 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()),
                 call->deopt_id(),
@@ -729,7 +729,7 @@
 }
 
 
-bool FlowGraphOptimizer::TryReplaceWithIndexedOp(InstanceCallInstr* call) {
+bool JitOptimizer::TryReplaceWithIndexedOp(InstanceCallInstr* call) {
   // Check for monomorphic IC data.
   if (!call->HasICData()) return false;
   const ICData& ic_data =
@@ -761,8 +761,8 @@
 // comparison. Conversion is only possible for strings of length one.
 // E.g., detect str[x] == "x"; and use an integer comparison of char-codes.
 // TODO(srdjan): Expand for two-byte and external strings.
-bool FlowGraphOptimizer::TryStringLengthOneEquality(InstanceCallInstr* call,
-                                                    Token::Kind op_kind) {
+bool JitOptimizer::TryStringLengthOneEquality(InstanceCallInstr* call,
+                                              Token::Kind op_kind) {
   ASSERT(HasOnlyTwoOf(*call->ic_data(), kOneByteStringCid));
   // Check that left and right are length one strings (either string constants
   // or results of string-from-char-code.
@@ -848,8 +848,8 @@
 
 static bool SmiFitsInDouble() { return kSmiBits < 53; }
 
-bool FlowGraphOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call,
-                                                  Token::Kind op_kind) {
+bool JitOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call,
+                                            Token::Kind op_kind) {
   const ICData& ic_data = *call->ic_data();
   ASSERT(ic_data.NumArgsTested() == 2);
 
@@ -957,8 +957,8 @@
 }
 
 
-bool FlowGraphOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call,
-                                                    Token::Kind op_kind) {
+bool JitOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call,
+                                              Token::Kind op_kind) {
   const ICData& ic_data = *call->ic_data();
   ASSERT(ic_data.NumArgsTested() == 2);
 
@@ -1019,8 +1019,8 @@
 }
 
 
-bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call,
-                                                Token::Kind op_kind) {
+bool JitOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call,
+                                          Token::Kind op_kind) {
   intptr_t operands_type = kIllegalCid;
   ASSERT(call->HasICData());
   const ICData& ic_data = *call->ic_data();
@@ -1228,8 +1228,8 @@
 }
 
 
-bool FlowGraphOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call,
-                                               Token::Kind op_kind) {
+bool JitOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call,
+                                         Token::Kind op_kind) {
   ASSERT(call->ArgumentCount() == 1);
   Definition* input = call->ArgumentAt(0);
   Definition* unary_op = NULL;
@@ -1262,15 +1262,20 @@
 }
 
 
-// Using field class
-RawField* FlowGraphOptimizer::GetField(intptr_t class_id,
-                                       const String& field_name) {
+// Using field class.
+RawField* JitOptimizer::GetField(intptr_t class_id,
+                                 const String& field_name) {
   Class& cls = Class::Handle(Z, isolate()->class_table()->At(class_id));
   Field& field = Field::Handle(Z);
   while (!cls.IsNull()) {
     field = cls.LookupInstanceField(field_name);
     if (!field.IsNull()) {
-      return field.raw();
+      if (Compiler::IsBackgroundCompilation() ||
+          FLAG_force_clone_compiler_objects) {
+        return field.CloneFromOriginal();
+      } else {
+        return field.raw();
+      }
     }
     cls = cls.SuperClass();
   }
@@ -1281,7 +1286,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
 // callee functions, then no class check is needed.
-bool FlowGraphOptimizer::InstanceCallNeedsClassCheck(
+bool JitOptimizer::InstanceCallNeedsClassCheck(
     InstanceCallInstr* call, RawFunction::Kind kind) const {
   if (!FLAG_use_cha_deopt && !isolate()->all_classes_finalized()) {
     // Even if class or function are private, lazy class finalization
@@ -1312,8 +1317,7 @@
 }
 
 
-bool FlowGraphOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call,
-                                                      bool allow_check) {
+bool JitOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) {
   ASSERT(call->HasICData());
   const ICData& ic_data = *call->ic_data();
   ASSERT(ic_data.HasOneTarget());
@@ -1328,9 +1332,6 @@
   ASSERT(!field.IsNull());
 
   if (InstanceCallNeedsClassCheck(call, RawFunction::kImplicitGetter)) {
-    if (!allow_check) {
-      return false;
-    }
     AddReceiverCheck(call);
   }
   LoadFieldInstr* load = new(Z) LoadFieldInstr(
@@ -1363,8 +1364,8 @@
 }
 
 
-bool FlowGraphOptimizer::InlineFloat32x4Getter(InstanceCallInstr* call,
-                                               MethodRecognizer::Kind getter) {
+bool JitOptimizer::InlineFloat32x4Getter(InstanceCallInstr* call,
+                                         MethodRecognizer::Kind getter) {
   if (!ShouldInlineSimd()) {
     return false;
   }
@@ -1438,8 +1439,8 @@
 }
 
 
-bool FlowGraphOptimizer::InlineFloat64x2Getter(InstanceCallInstr* call,
-                                               MethodRecognizer::Kind getter) {
+bool JitOptimizer::InlineFloat64x2Getter(InstanceCallInstr* call,
+                                         MethodRecognizer::Kind getter) {
   if (!ShouldInlineSimd()) {
     return false;
   }
@@ -1464,8 +1465,8 @@
 }
 
 
-bool FlowGraphOptimizer::InlineInt32x4Getter(InstanceCallInstr* call,
-                                              MethodRecognizer::Kind getter) {
+bool JitOptimizer::InlineInt32x4Getter(InstanceCallInstr* call,
+                                       MethodRecognizer::Kind getter) {
   if (!ShouldInlineSimd()) {
     return false;
   }
@@ -1539,8 +1540,8 @@
 }
 
 
-bool FlowGraphOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call,
-                                                 Token::Kind op_kind) {
+bool JitOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call,
+                                           Token::Kind op_kind) {
   if (!ShouldInlineSimd()) {
     return false;
   }
@@ -1572,8 +1573,8 @@
 }
 
 
-bool FlowGraphOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call,
-                                                Token::Kind op_kind) {
+bool JitOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call,
+                                         Token::Kind op_kind) {
   if (!ShouldInlineSimd()) {
     return false;
   }
@@ -1604,8 +1605,8 @@
 }
 
 
-bool FlowGraphOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call,
-                                                 Token::Kind op_kind) {
+bool JitOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call,
+                                           Token::Kind op_kind) {
   if (!ShouldInlineSimd()) {
     return false;
   }
@@ -1637,9 +1638,7 @@
 
 
 // Only unique implicit instance getters can be currently handled.
-// Returns false if 'allow_check' is false and a check is needed.
-bool FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call,
-                                                 bool allow_check) {
+bool JitOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) {
   ASSERT(call->HasICData());
   const ICData& ic_data = *call->ic_data();
   if (ic_data.NumberOfUsedChecks() == 0) {
@@ -1659,11 +1658,11 @@
     // inlining in FlowGraphInliner.
     return false;
   }
-  return InlineImplicitInstanceGetter(call, allow_check);
+  return InlineImplicitInstanceGetter(call);
 }
 
 
-bool FlowGraphOptimizer::TryReplaceInstanceCallWithInline(
+bool JitOptimizer::TryReplaceInstanceCallWithInline(
     InstanceCallInstr* call) {
   Function& target = Function::Handle(Z);
   GrowableArray<intptr_t> class_ids;
@@ -1707,7 +1706,7 @@
 }
 
 
-void FlowGraphOptimizer::ReplaceWithMathCFunction(
+void JitOptimizer::ReplaceWithMathCFunction(
     InstanceCallInstr* call,
     MethodRecognizer::Kind recognized_kind) {
   AddReceiverCheck(call);
@@ -1748,7 +1747,7 @@
 
 
 // Inline only simple, frequently called core library methods.
-bool FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
+bool JitOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
   ASSERT(call->HasICData());
   const ICData& ic_data = *call->ic_data();
   if ((ic_data.NumberOfUsedChecks() == 0) || !ic_data.HasOneTarget()) {
@@ -1981,7 +1980,7 @@
 }
 
 
-bool FlowGraphOptimizer::TryInlineFloat32x4Constructor(
+bool JitOptimizer::TryInlineFloat32x4Constructor(
     StaticCallInstr* call,
     MethodRecognizer::Kind recognized_kind) {
   if (!ShouldInlineSimd()) {
@@ -2024,7 +2023,7 @@
 }
 
 
-bool FlowGraphOptimizer::TryInlineFloat64x2Constructor(
+bool JitOptimizer::TryInlineFloat64x2Constructor(
     StaticCallInstr* call,
     MethodRecognizer::Kind recognized_kind) {
   if (!ShouldInlineSimd()) {
@@ -2059,7 +2058,7 @@
 }
 
 
-bool FlowGraphOptimizer::TryInlineInt32x4Constructor(
+bool JitOptimizer::TryInlineInt32x4Constructor(
     StaticCallInstr* call,
     MethodRecognizer::Kind recognized_kind) {
   if (!ShouldInlineSimd()) {
@@ -2096,7 +2095,7 @@
 }
 
 
-bool FlowGraphOptimizer::TryInlineFloat32x4Method(
+bool JitOptimizer::TryInlineFloat32x4Method(
     InstanceCallInstr* call,
     MethodRecognizer::Kind recognized_kind) {
   if (!ShouldInlineSimd()) {
@@ -2260,7 +2259,7 @@
 }
 
 
-bool FlowGraphOptimizer::TryInlineFloat64x2Method(
+bool JitOptimizer::TryInlineFloat64x2Method(
     InstanceCallInstr* call,
     MethodRecognizer::Kind recognized_kind) {
   if (!ShouldInlineSimd()) {
@@ -2319,7 +2318,7 @@
 }
 
 
-bool FlowGraphOptimizer::TryInlineInt32x4Method(
+bool JitOptimizer::TryInlineInt32x4Method(
     InstanceCallInstr* call,
     MethodRecognizer::Kind recognized_kind) {
   if (!ShouldInlineSimd()) {
@@ -2390,7 +2389,7 @@
 // If no mapping is possible, 'results' is empty.
 // An instance-of test returning all same results can be converted to a class
 // check.
-RawBool* FlowGraphOptimizer::InstanceOfAsBool(
+RawBool* JitOptimizer::InstanceOfAsBool(
     const ICData& ic_data,
     const AbstractType& type,
     ZoneGrowableArray<intptr_t>* results) const {
@@ -2449,7 +2448,7 @@
 
 
 // Returns true if checking against this type is a direct class id comparison.
-bool FlowGraphOptimizer::TypeCheckAsClassEquality(const AbstractType& type) {
+bool JitOptimizer::TypeCheckAsClassEquality(const AbstractType& type) {
   ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded());
   // Requires CHA.
   if (!type.IsInstantiated()) return false;
@@ -2553,7 +2552,7 @@
 
 
 // TODO(srdjan): Use ICData to check if always true or false.
-void FlowGraphOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) {
+void JitOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) {
   ASSERT(Token::IsTypeTestOperator(call->token_kind()));
   Definition* left = call->ArgumentAt(0);
   Definition* type_args = NULL;
@@ -2661,7 +2660,7 @@
 
 
 // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids).
-void FlowGraphOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) {
+void JitOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) {
   ASSERT(Token::IsTypeCastOperator(call->token_kind()));
   Definition* left = call->ArgumentAt(0);
   Definition* type_args = call->ArgumentAt(1);
@@ -2704,154 +2703,9 @@
 }
 
 
-bool FlowGraphOptimizer::IsBlackListedForInlining(intptr_t call_deopt_id) {
-  for (intptr_t i = 0; i < inlining_black_list_->length(); ++i) {
-    if ((*inlining_black_list_)[i] == call_deopt_id) return true;
-  }
-  return false;
-}
-
-// Special optimizations when running in --noopt mode.
-void FlowGraphOptimizer::InstanceCallNoopt(InstanceCallInstr* instr) {
-  // TODO(srdjan): Investigate other attempts, as they are not allowed to
-  // deoptimize.
-
-  // Type test is special as it always gets converted into inlined code.
-  const Token::Kind op_kind = instr->token_kind();
-  if (Token::IsTypeTestOperator(op_kind)) {
-    ReplaceWithInstanceOf(instr);
-    return;
-  }
-  if (Token::IsTypeCastOperator(op_kind)) {
-    ReplaceWithTypeCast(instr);
-    return;
-  }
-
-  if ((op_kind == Token::kGET) &&
-      TryInlineInstanceGetter(instr, false /* no checks allowed */)) {
-    return;
-  }
-  const ICData& unary_checks =
-      ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks());
-  if ((unary_checks.NumberOfChecks() > 0) &&
-      (op_kind == Token::kSET) &&
-      TryInlineInstanceSetter(instr, unary_checks, false /* no checks */)) {
-    return;
-  }
-
-  if (use_speculative_inlining_ &&
-      !IsBlackListedForInlining(instr->deopt_id()) &&
-      (unary_checks.NumberOfChecks() > 0)) {
-    if ((op_kind == Token::kINDEX) && TryReplaceWithIndexedOp(instr)) {
-      return;
-    }
-    if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithIndexedOp(instr)) {
-      return;
-    }
-    if ((op_kind == Token::kEQ) && TryReplaceWithEqualityOp(instr, op_kind)) {
-      return;
-    }
-
-    if (Token::IsRelationalOperator(op_kind) &&
-        TryReplaceWithRelationalOp(instr, op_kind)) {
-      return;
-    }
-
-    if (Token::IsBinaryOperator(op_kind) &&
-        TryReplaceWithBinaryOp(instr, op_kind)) {
-      return;
-    }
-    if (Token::IsUnaryOperator(op_kind) &&
-        TryReplaceWithUnaryOp(instr, op_kind)) {
-      return;
-    }
-  }
-
-  bool has_one_target =
-      (unary_checks.NumberOfChecks() > 0) && unary_checks.HasOneTarget();
-  if (has_one_target) {
-    // Check if the single target is a polymorphic target, if it is,
-    // we don't have one target.
-    const Function& target =
-        Function::Handle(Z, unary_checks.GetTargetAt(0));
-    const bool polymorphic_target = MethodRecognizer::PolymorphicTarget(target);
-    has_one_target = !polymorphic_target;
-  }
-
-  if (has_one_target) {
-    RawFunction::Kind function_kind =
-        Function::Handle(Z, unary_checks.GetTargetAt(0)).kind();
-    if (!InstanceCallNeedsClassCheck(instr, function_kind)) {
-      PolymorphicInstanceCallInstr* call =
-          new(Z) PolymorphicInstanceCallInstr(instr, unary_checks,
-                                              /* with_checks = */ false);
-      instr->ReplaceWith(call, current_iterator());
-      return;
-    }
-  }
-
-  // More than one targets. Generate generic polymorphic call without
-  // deoptimization.
-  if (instr->ic_data()->NumberOfUsedChecks() > 0) {
-    ASSERT(!FLAG_polymorphic_with_deopt);
-    // OK to use checks with PolymorphicInstanceCallInstr since no
-    // deoptimization is allowed.
-    PolymorphicInstanceCallInstr* call =
-        new(Z) PolymorphicInstanceCallInstr(instr, unary_checks,
-                                            /* with_checks = */ true);
-    instr->ReplaceWith(call, current_iterator());
-    return;
-  }
-
-  // No IC data checks. Try resolve target using the propagated type.
-  // If the propagated type has a method with the target name and there are
-  // no overrides with that name according to CHA, call the method directly.
-  const intptr_t receiver_cid =
-      instr->PushArgumentAt(0)->value()->Type()->ToCid();
-  if (receiver_cid == kDynamicCid) return;
-  const Class& receiver_class = Class::Handle(Z,
-      isolate()->class_table()->At(receiver_cid));
-
-  const Array& args_desc_array = Array::Handle(Z,
-      ArgumentsDescriptor::New(instr->ArgumentCount(),
-                               instr->argument_names()));
-  ArgumentsDescriptor args_desc(args_desc_array);
-  const Function& function = Function::Handle(Z,
-      Resolver::ResolveDynamicForReceiverClass(
-          receiver_class,
-          instr->function_name(),
-          args_desc));
-  if (function.IsNull()) {
-    return;
-  }
-  if (!thread()->cha()->HasOverride(receiver_class, instr->function_name())) {
-    if (FLAG_trace_cha) {
-      THR_Print("  **(CHA) Instance call needs no check, "
-          "no overrides of '%s' '%s'\n",
-          instr->function_name().ToCString(), receiver_class.ToCString());
-    }
-    thread()->cha()->AddToLeafClasses(receiver_class);
-
-    // Create fake IC data with the resolved target.
-    const ICData& ic_data = ICData::Handle(
-        ICData::New(flow_graph_->function(),
-                    instr->function_name(),
-                    args_desc_array,
-                    Thread::kNoDeoptId,
-                    /* args_tested = */ 1));
-    ic_data.AddReceiverCheck(receiver_class.id(), function);
-    PolymorphicInstanceCallInstr* call =
-        new(Z) PolymorphicInstanceCallInstr(instr, ic_data,
-                                            /* with_checks = */ false);
-    instr->ReplaceWith(call, current_iterator());
-    return;
-  }
-}
-
-
 // Tries to optimize instance call by replacing it with a faster instruction
 // (e.g, binary op, field load, ..).
-void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
+void JitOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
   if (!instr->HasICData() || (instr->ic_data()->NumberOfUsedChecks() == 0)) {
     return;
   }
@@ -2957,7 +2811,7 @@
 }
 
 
-void FlowGraphOptimizer::VisitStaticCall(StaticCallInstr* call) {
+void JitOptimizer::VisitStaticCall(StaticCallInstr* call) {
   if (!CanUnboxDouble()) {
     return;
   }
@@ -3130,7 +2984,7 @@
 }
 
 
-void FlowGraphOptimizer::VisitStoreInstanceField(
+void JitOptimizer::VisitStoreInstanceField(
     StoreInstanceFieldInstr* instr) {
   if (instr->IsUnboxedStore()) {
     ASSERT(instr->is_potential_unboxed_initialization_);
@@ -3139,9 +2993,9 @@
     // usage count of at least 1/kGetterSetterRatio of the getter usage count.
     // This is to avoid unboxing fields where the setter is never or rarely
     // executed.
-    const Field& field = Field::ZoneHandle(Z, instr->field().raw());
+    const Field& field = Field::ZoneHandle(Z, instr->field().Original());
     const String& field_name = String::Handle(Z, field.name());
-    const Class& owner = Class::Handle(Z, field.owner());
+    const Class& owner = Class::Handle(Z, field.Owner());
     const Function& getter =
         Function::Handle(Z, owner.LookupGetterFunction(field_name));
     const Function& setter =
@@ -3184,7 +3038,7 @@
 }
 
 
-void FlowGraphOptimizer::VisitAllocateContext(AllocateContextInstr* instr) {
+void JitOptimizer::VisitAllocateContext(AllocateContextInstr* instr) {
   // Replace generic allocation with a sequence of inlined allocation and
   // explicit initalizing stores.
   AllocateUninitializedContextInstr* replacement =
@@ -3219,7 +3073,7 @@
 }
 
 
-void FlowGraphOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) {
+void JitOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) {
   // TODO(zerny): Use kUnboxedUint32 once it is fully supported/optimized.
 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM)
   if (!instr->can_pack_into_smi())
@@ -3228,12 +3082,11 @@
 }
 
 
-bool FlowGraphOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr,
-                                                 const ICData& unary_ic_data,
-                                                 bool allow_checks) {
+bool JitOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr,
+                                           const ICData& unary_ic_data) {
   ASSERT((unary_ic_data.NumberOfChecks() > 0) &&
       (unary_ic_data.NumArgsTested() == 1));
-  if (I->flags().type_checks()) {
+  if (I->type_checks()) {
     // Checked mode setters are inlined like normal methods by conventional
     // inlining.
     return false;
@@ -3264,15 +3117,9 @@
   ASSERT(!field.IsNull());
 
   if (InstanceCallNeedsClassCheck(instr, RawFunction::kImplicitSetter)) {
-    if (!allow_checks) {
-      return false;
-    }
     AddReceiverCheck(instr);
   }
   if (field.guarded_cid() != kDynamicCid) {
-    if (!allow_checks) {
-      return false;
-    }
     InsertBefore(instr,
                  new(Z) GuardFieldClassInstr(
                      new(Z) Value(instr->ArgumentAt(1)),
@@ -3283,9 +3130,6 @@
   }
 
   if (field.needs_length_check()) {
-    if (!allow_checks) {
-      return false;
-    }
     InsertBefore(instr,
                  new(Z) GuardFieldLengthInstr(
                      new(Z) Value(instr->ArgumentAt(1)),
diff --git a/runtime/vm/flow_graph_optimizer.h b/runtime/vm/jit_optimizer.h
similarity index 85%
rename from runtime/vm/flow_graph_optimizer.h
rename to runtime/vm/jit_optimizer.h
index 544d7de..ebddc78 100644
--- a/runtime/vm/flow_graph_optimizer.h
+++ b/runtime/vm/jit_optimizer.h
@@ -2,8 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-#ifndef VM_FLOW_GRAPH_OPTIMIZER_H_
-#define VM_FLOW_GRAPH_OPTIMIZER_H_
+#ifndef VM_JIT_OPTIMIZER_H_
+#define VM_JIT_OPTIMIZER_H_
 
 #include "vm/intermediate_language.h"
 #include "vm/flow_graph.h"
@@ -14,19 +14,13 @@
 template <typename T> class GrowableArray;
 class ParsedFunction;
 
-class FlowGraphOptimizer : public FlowGraphVisitor {
+class JitOptimizer : public FlowGraphVisitor {
  public:
-  FlowGraphOptimizer(
-      FlowGraph* flow_graph,
-      bool use_speculative_inlining,
-      GrowableArray<intptr_t>* inlining_black_list)
+  explicit JitOptimizer(FlowGraph* flow_graph)
       : FlowGraphVisitor(flow_graph->reverse_postorder()),
-        flow_graph_(flow_graph),
-        use_speculative_inlining_(use_speculative_inlining),
-        inlining_black_list_(inlining_black_list) {
-    ASSERT(!use_speculative_inlining || (inlining_black_list != NULL));
-  }
-  virtual ~FlowGraphOptimizer() {}
+        flow_graph_(flow_graph) { }
+
+  virtual ~JitOptimizer() {}
 
   FlowGraph* flow_graph() const { return flow_graph_; }
 
@@ -70,11 +64,9 @@
   bool TryReplaceWithEqualityOp(InstanceCallInstr* call, Token::Kind op_kind);
   bool TryReplaceWithRelationalOp(InstanceCallInstr* call, Token::Kind op_kind);
 
-  bool TryInlineInstanceGetter(InstanceCallInstr* call,
-                               bool allow_check = true);
+  bool TryInlineInstanceGetter(InstanceCallInstr* call);
   bool TryInlineInstanceSetter(InstanceCallInstr* call,
-                               const ICData& unary_ic_data,
-                               bool allow_check = true);
+                               const ICData& unary_ic_data);
 
   bool TryInlineInstanceMethod(InstanceCallInstr* call);
   bool TryInlineFloat32x4Constructor(StaticCallInstr* call,
@@ -138,7 +130,7 @@
                               Token::Kind op_kind);
   bool InlineFloat64x2BinaryOp(InstanceCallInstr* call,
                                Token::Kind op_kind);
-  bool InlineImplicitInstanceGetter(InstanceCallInstr* call, bool allow_check);
+  bool InlineImplicitInstanceGetter(InstanceCallInstr* call);
 
   RawBool* InstanceOfAsBool(const ICData& ic_data,
                             const AbstractType& type,
@@ -157,8 +149,6 @@
                                        Representation rep, intptr_t cid);
   bool TryStringLengthOneEquality(InstanceCallInstr* call, Token::Kind op_kind);
 
-  void InstanceCallNoopt(InstanceCallInstr* instr);
-
   RawField* GetField(intptr_t class_id, const String& field_name);
 
   Thread* thread() const { return flow_graph_->thread(); }
@@ -167,18 +157,12 @@
 
   const Function& function() const { return flow_graph_->function(); }
 
-  bool IsBlackListedForInlining(intptr_t deopt_id);
-
   FlowGraph* flow_graph_;
 
-  const bool use_speculative_inlining_;
-
-  GrowableArray<intptr_t>* inlining_black_list_;
-
-  DISALLOW_COPY_AND_ASSIGN(FlowGraphOptimizer);
+  DISALLOW_COPY_AND_ASSIGN(JitOptimizer);
 };
 
 
 }  // namespace dart
 
-#endif  // VM_FLOW_GRAPH_OPTIMIZER_H_
+#endif  // VM_JIT_OPTIMIZER_H_
diff --git a/runtime/vm/lockers.cc b/runtime/vm/lockers.cc
index 839d40c..2efe245 100644
--- a/runtime/vm/lockers.cc
+++ b/runtime/vm/lockers.cc
@@ -9,6 +9,23 @@
 namespace dart {
 
 
+static void updateThreadState(Thread* thread) {
+  // First try a fast update of the thread state to indicate it is not at a
+  // safepoint anymore.
+  uword old_state = Thread::SetAtSafepoint(true, 0);
+  uword addr =
+      reinterpret_cast<uword>(thread) + Thread::safepoint_state_offset();
+  if (AtomicOperations::CompareAndSwapWord(
+          reinterpret_cast<uword*>(addr), old_state, 0) != old_state) {
+    // Fast update failed which means we could potentially be in the middle
+    // of a safepoint operation and need to block for it.
+    SafepointHandler* handler = thread->isolate()->safepoint_handler();
+    handler->ExitSafepointUsingLock(thread);
+  }
+  thread->set_execution_state(Thread::kThreadInVM);
+}
+
+
 Monitor::WaitResult MonitorLocker::WaitWithSafepointCheck(Thread* thread,
                                                           int64_t millis) {
   ASSERT(thread == Thread::Current());
@@ -40,9 +57,45 @@
     // We did not get the lock and could potentially block, so transition
     // accordingly.
     Thread* thread = Thread::Current();
+    if (thread != NULL) {
+      thread->set_execution_state(Thread::kThreadInBlockedState);
+      thread->EnterSafepoint();
+      mutex->Lock();
+      // Update thread state and block if a safepoint operation is in progress.
+      updateThreadState(thread);
+    } else {
+      mutex->Lock();
+    }
+  }
+}
+
+
+SafepointMonitorLocker::SafepointMonitorLocker(Monitor* monitor)
+    : monitor_(monitor) {
+  ASSERT(monitor_ != NULL);
+  if (!monitor_->TryEnter()) {
+    // We did not get the lock and could potentially block, so transition
+    // accordingly.
+    Thread* thread = Thread::Current();
+    if (thread != NULL) {
+      thread->set_execution_state(Thread::kThreadInBlockedState);
+      thread->EnterSafepoint();
+      monitor_->Enter();
+      // Update thread state and block if a safepoint operation is in progress.
+      updateThreadState(thread);
+    } else {
+      monitor_->Enter();
+    }
+  }
+}
+
+
+Monitor::WaitResult SafepointMonitorLocker::Wait(int64_t millis) {
+  Thread* thread = Thread::Current();
+  if (thread != NULL) {
     thread->set_execution_state(Thread::kThreadInBlockedState);
     thread->EnterSafepoint();
-    mutex->Lock();
+    Monitor::WaitResult result = monitor_->Wait(millis);
     // First try a fast update of the thread state to indicate it is not at a
     // safepoint anymore.
     uword old_state = Thread::SetAtSafepoint(true, 0);
@@ -52,10 +105,15 @@
             reinterpret_cast<uword*>(addr), old_state, 0) != old_state) {
       // Fast update failed which means we could potentially be in the middle
       // of a safepoint operation and need to block for it.
+      monitor_->Exit();
       SafepointHandler* handler = thread->isolate()->safepoint_handler();
       handler->ExitSafepointUsingLock(thread);
+      monitor_->Enter();
     }
     thread->set_execution_state(Thread::kThreadInVM);
+    return result;
+  } else {
+    return monitor_->Wait(millis);
   }
 }
 
diff --git a/runtime/vm/lockers.h b/runtime/vm/lockers.h
index fd324f4..a0b1a17 100644
--- a/runtime/vm/lockers.h
+++ b/runtime/vm/lockers.h
@@ -13,37 +13,156 @@
 
 namespace dart {
 
+const bool kNoSafepointScope = true;
+const bool kDontAssertNoSafepointScope = false;
+
+/*
+ * Normal mutex locker :
+ * This locker abstraction should only be used when the enclosing code can
+ * not trigger a safepoint. In debug mode this class increments the
+ * no_safepoint_scope_depth variable for the current thread when the lock is
+ * taken and decrements it when the lock is released. NOTE: please do not use
+ * the passed in mutex object independent of the locker class, For example the
+ * code below will not assert correctly:
+ *    {
+ *      MutexLocker ml(m);
+ *      ....
+ *      m->Exit();
+ *      ....
+ *      m->Enter();
+ *      ...
+ *    }
+ * Always use the locker object even when the lock needs to be released
+ * temporarily, e.g:
+ *    {
+ *      MutexLocker ml(m);
+ *      ....
+ *      ml.Exit();
+ *      ....
+ *      ml.Enter();
+ *      ...
+ *    }
+ */
 class MutexLocker : public ValueObject {
  public:
-  explicit MutexLocker(Mutex* mutex) : mutex_(mutex) {
+  explicit MutexLocker(Mutex* mutex, bool no_safepoint_scope = true)
+      : mutex_(mutex), no_safepoint_scope_(no_safepoint_scope) {
     ASSERT(mutex != NULL);
-    // TODO(iposva): Consider adding a no GC scope here.
+#if defined(DEBUG)
+    if (no_safepoint_scope_) {
+      Thread* thread = Thread::Current();
+      if (thread != NULL) {
+        thread->IncrementNoSafepointScopeDepth();
+      } else {
+        no_safepoint_scope_ = false;
+      }
+    }
+#endif
     mutex_->Lock();
   }
 
   virtual ~MutexLocker() {
     mutex_->Unlock();
-    // TODO(iposva): Consider decrementing the no GC scope here.
+#if defined(DEBUG)
+    if (no_safepoint_scope_) {
+      Thread::Current()->DecrementNoSafepointScopeDepth();
+    }
+#endif
+  }
+
+  void Lock() const {
+#if defined(DEBUG)
+    if (no_safepoint_scope_) {
+      Thread::Current()->IncrementNoSafepointScopeDepth();
+    }
+#endif
+    mutex_->Lock();
+  }
+  void Unlock() const {
+    mutex_->Unlock();
+#if defined(DEBUG)
+    if (no_safepoint_scope_) {
+      Thread::Current()->DecrementNoSafepointScopeDepth();
+    }
+#endif
   }
 
  private:
   Mutex* const mutex_;
+  bool no_safepoint_scope_;
 
   DISALLOW_COPY_AND_ASSIGN(MutexLocker);
 };
 
-
+/*
+ * Normal monitor locker :
+ * This locker abstraction should only be used when the enclosing code can
+ * not trigger a safepoint. In debug mode this class increments the
+ * no_safepoint_scope_depth variable for the current thread when the lock is
+ * taken and decrements it when the lock is released. NOTE: please do not use
+ * the passed in mutex object independent of the locker class, For example the
+ * code below will not assert correctly:
+ *    {
+ *      MonitorLocker ml(m);
+ *      ....
+ *      m->Exit();
+ *      ....
+ *      m->Enter();
+ *      ...
+ *    }
+ * Always use the locker object even when the lock needs to be released
+ * temporarily, e.g:
+ *    {
+ *      MonitorLocker ml(m);
+ *      ....
+ *      ml.Exit();
+ *      ....
+ *      ml.Enter();
+ *      ...
+ *    }
+ */
 class MonitorLocker : public ValueObject {
  public:
-  explicit MonitorLocker(Monitor* monitor) : monitor_(monitor) {
+  explicit MonitorLocker(Monitor* monitor, bool no_safepoint_scope = true)
+      : monitor_(monitor), no_safepoint_scope_(no_safepoint_scope) {
     ASSERT(monitor != NULL);
-    // TODO(iposva): Consider adding a no GC scope here.
+#if defined(DEBUG)
+    if (no_safepoint_scope_) {
+      Thread* thread = Thread::Current();
+      if (thread != NULL) {
+        thread->IncrementNoSafepointScopeDepth();
+      } else {
+        no_safepoint_scope_ = false;
+      }
+    }
+#endif
     monitor_->Enter();
   }
 
   virtual ~MonitorLocker() {
     monitor_->Exit();
-    // TODO(iposva): Consider decrementing the no GC scope here.
+#if defined(DEBUG)
+    if (no_safepoint_scope_) {
+      Thread::Current()->DecrementNoSafepointScopeDepth();
+    }
+#endif
+  }
+
+  void Enter() const {
+#if defined(DEBUG)
+    if (no_safepoint_scope_) {
+      Thread::Current()->IncrementNoSafepointScopeDepth();
+    }
+#endif
+    monitor_->Enter();
+  }
+  void Exit() const {
+    monitor_->Exit();
+#if defined(DEBUG)
+    if (no_safepoint_scope_) {
+      Thread::Current()->DecrementNoSafepointScopeDepth();
+    }
+#endif
   }
 
   Monitor::WaitResult Wait(int64_t millis = Monitor::kNoTimeout) {
@@ -67,16 +186,29 @@
 
  private:
   Monitor* const monitor_;
+  bool no_safepoint_scope_;
 
   DISALLOW_COPY_AND_ASSIGN(MonitorLocker);
 };
 
-
-// SafepointMutexLocker objects are used in code where the locks are
-// more coarse grained and a safepoint operation could be potentially
-// triggered while holding this lock. This ensures that other threads
-// which try to acquire the same lock will be marked as being at a
-// safepoint when they are blocked.
+/*
+ * Safepoint mutex locker :
+ * This locker abstraction should be used when the enclosing code could
+ * potentially trigger a safepoint.
+ * This locker ensures that other threads that try to acquire the same lock
+ * will be marked as being at a safepoint if they get blocked trying to
+ * acquire the lock.
+ * NOTE: please do not use the passed in mutex object independent of the locker
+ * class, For example the code below will not work correctly:
+ *    {
+ *      SafepointMutexLocker ml(m);
+ *      ....
+ *      m->Exit();
+ *      ....
+ *      m->Enter();
+ *      ...
+ *    }
+ */
 class SafepointMutexLocker : public ValueObject {
  public:
   explicit SafepointMutexLocker(Mutex* mutex);
@@ -90,6 +222,39 @@
   DISALLOW_COPY_AND_ASSIGN(SafepointMutexLocker);
 };
 
+/*
+ * Safepoint monitor locker :
+ * This locker abstraction should be used when the enclosing code could
+ * potentially trigger a safepoint.
+ * This locker ensures that other threads that try to acquire the same lock
+ * will be marked as being at a safepoint if they get blocked trying to
+ * acquire the lock.
+ * NOTE: please do not use the passed in monitor object independent of the
+ * locker class, For example the code below will not work correctly:
+ *    {
+ *      SafepointMonitorLocker ml(m);
+ *      ....
+ *      m->Exit();
+ *      ....
+ *      m->Enter();
+ *      ...
+ *    }
+ */
+class SafepointMonitorLocker : public ValueObject {
+ public:
+  explicit SafepointMonitorLocker(Monitor* monitor);
+  virtual ~SafepointMonitorLocker() {
+    monitor_->Exit();
+  }
+
+  Monitor::WaitResult Wait(int64_t millis = Monitor::kNoTimeout);
+
+ private:
+  Monitor* const monitor_;
+
+  DISALLOW_COPY_AND_ASSIGN(SafepointMonitorLocker);
+};
+
 }  // namespace dart
 
 
diff --git a/runtime/vm/megamorphic_cache_table.cc b/runtime/vm/megamorphic_cache_table.cc
index 062941e..6c4ccf1 100644
--- a/runtime/vm/megamorphic_cache_table.cc
+++ b/runtime/vm/megamorphic_cache_table.cc
@@ -16,7 +16,7 @@
                                                    const String& name,
                                                    const Array& descriptor) {
   // Multiple compilation threads could access this lookup.
-  MutexLocker ml(isolate->mutex());
+  SafepointMutexLocker ml(isolate->mutex());
   ASSERT(name.IsSymbol());
   // TODO(rmacnak): ASSERT(descriptor.IsCanonical());
 
diff --git a/runtime/vm/message_handler.cc b/runtime/vm/message_handler.cc
index e64a05a..c1a9980 100644
--- a/runtime/vm/message_handler.cc
+++ b/runtime/vm/message_handler.cc
@@ -176,6 +176,7 @@
 
 
 MessageHandler::MessageStatus MessageHandler::HandleMessages(
+    MonitorLocker* ml,
     bool allow_normal_messages,
     bool allow_multiple_normal_messages) {
   // TODO(turnidge): Add assert that monitor_ is held here.
@@ -200,7 +201,7 @@
 
     // Release the monitor_ temporarily while we handle the message.
     // The monitor was acquired in MessageHandler::TaskCallback().
-    monitor_.Exit();
+    ml->Exit();
     Message::Priority saved_priority = message->priority();
     Dart_Port saved_dest_port = message->dest_port();
     MessageStatus status = HandleMessage(message);
@@ -208,7 +209,7 @@
       max_status = status;
     }
     message = NULL;  // May be deleted by now.
-    monitor_.Enter();
+    ml->Enter();
     if (FLAG_trace_isolates) {
       OS::Print("[.] Message handled (%s):\n"
                 "\tlen:        %" Pd "\n"
@@ -254,7 +255,7 @@
 #if defined(DEBUG)
   CheckAccess();
 #endif
-  return HandleMessages(true, false);
+  return HandleMessages(&ml, true, false);
 }
 
 
@@ -266,7 +267,7 @@
 #if defined(DEBUG)
   CheckAccess();
 #endif
-  return HandleMessages(true, true);
+  return HandleMessages(&ml, true, true);
 }
 
 
@@ -278,7 +279,7 @@
 #if defined(DEBUG)
   CheckAccess();
 #endif
-  return HandleMessages(false, false);
+  return HandleMessages(&ml, false, false);
 }
 
 
@@ -327,7 +328,7 @@
         PausedOnStartLocked(true);
       }
       // More messages may have come in before we (re)acquired the monitor.
-      status = HandleMessages(false, false);
+      status = HandleMessages(&ml, false, false);
       if (ShouldPauseOnStart(status)) {
         // Still paused.
         ASSERT(oob_queue_->IsEmpty());
@@ -345,16 +346,16 @@
         // main() function.
         //
         // Release the monitor_ temporarily while we call the start callback.
-        monitor_.Exit();
+        ml.Exit();
         status = start_callback_(callback_data_);
         ASSERT(Isolate::Current() == NULL);
         start_callback_ = NULL;
-        monitor_.Enter();
+        ml.Enter();
       }
 
       // Handle any pending messages for this message handler.
       if (status != kShutdown) {
-        status = HandleMessages((status == kOK), true);
+        status = HandleMessages(&ml, (status == kOK), true);
       }
     }
 
@@ -369,7 +370,7 @@
           }
           PausedOnExitLocked(true);
           // More messages may have come in while we released the monitor.
-          status = HandleMessages(false, false);
+          status = HandleMessages(&ml, false, false);
         }
         if (ShouldPauseOnExit(status)) {
           // Still paused.
diff --git a/runtime/vm/message_handler.h b/runtime/vm/message_handler.h
index 47dfa99..6f01328 100644
--- a/runtime/vm/message_handler.h
+++ b/runtime/vm/message_handler.h
@@ -12,6 +12,9 @@
 
 namespace dart {
 
+// Forward declarations.
+class MonitorLocker;
+
 // A MessageHandler is an entity capable of accepting messages.
 class MessageHandler {
  protected:
@@ -225,7 +228,8 @@
   void ClearOOBQueue();
 
   // Handles any pending messages.
-  MessageStatus HandleMessages(bool allow_normal_messages,
+  MessageStatus HandleMessages(MonitorLocker* ml,
+                               bool allow_normal_messages,
                                bool allow_multiple_normal_messages);
 
   Monitor monitor_;  // Protects all fields in MessageHandler.
diff --git a/runtime/vm/method_recognizer.h b/runtime/vm/method_recognizer.h
index 5547282..87a524e 100644
--- a/runtime/vm/method_recognizer.h
+++ b/runtime/vm/method_recognizer.h
@@ -13,310 +13,307 @@
 // When adding a new function add a 0 as fingerprint, build and run to get the
 // correct fingerprint from the mismatch error.
 #define OTHER_RECOGNIZED_LIST(V)                                               \
-  V(::, identical, ObjectIdentical, 554128144)                                 \
-  V(ClassID, getID, ClassIDgetID, 535124072)                                   \
-  V(Object, Object., ObjectConstructor, 1852396454)                            \
-  V(_List, ., ObjectArrayAllocate, 850375012)                                  \
-  V(_TypedList, _getInt8, ByteArrayBaseGetInt8, 1541411498)                    \
-  V(_TypedList, _getUint8, ByteArrayBaseGetUint8, 1032404349)                  \
-  V(_TypedList, _getInt16, ByteArrayBaseGetInt16, 381073990)                   \
-  V(_TypedList, _getUint16, ByteArrayBaseGetUint16, 1142676276)                \
-  V(_TypedList, _getInt32, ByteArrayBaseGetInt32, 330269934)                   \
-  V(_TypedList, _getUint32, ByteArrayBaseGetUint32, 59490554)                  \
-  V(_TypedList, _getInt64, ByteArrayBaseGetInt64, 322272622)                   \
-  V(_TypedList, _getFloat32, ByteArrayBaseGetFloat32, 393003933)               \
-  V(_TypedList, _getFloat64, ByteArrayBaseGetFloat64, 1792407200)              \
-  V(_TypedList, _getFloat32x4, ByteArrayBaseGetFloat32x4, 1338379857)          \
-  V(_TypedList, _getInt32x4, ByteArrayBaseGetInt32x4, 1469917805)              \
-  V(_TypedList, _setInt8, ByteArrayBaseSetInt8, 1892735922)                    \
-  V(_TypedList, _setUint8, ByteArrayBaseSetUint8, 1608794041)                  \
-  V(_TypedList, _setInt16, ByteArrayBaseSetInt16, 117380972)                   \
-  V(_TypedList, _setUint16, ByteArrayBaseSetUint16, 200484754)                 \
-  V(_TypedList, _setInt32, ByteArrayBaseSetInt32, 1020151991)                  \
-  V(_TypedList, _setUint32, ByteArrayBaseSetUint32, 1175056602)                \
-  V(_TypedList, _setInt64, ByteArrayBaseSetInt64, 784983863)                   \
-  V(_TypedList, _setFloat32, ByteArrayBaseSetFloat32, 460607665)               \
-  V(_TypedList, _setFloat64, ByteArrayBaseSetFloat64, 284787790)               \
-  V(_TypedList, _setFloat32x4, ByteArrayBaseSetFloat32x4, 262426120)           \
-  V(_TypedList, _setInt32x4, ByteArrayBaseSetInt32x4, 613041888)               \
-  V(_StringBase, _interpolate, StringBaseInterpolate, 1214901263)              \
-  V(_IntegerImplementation, toDouble, IntegerToDouble, 826404440)              \
+  V(::, identical, ObjectIdentical, 317103244)                                 \
+  V(ClassID, getID, ClassIDgetID, 1385157717)                                  \
+  V(Object, Object., ObjectConstructor, 1746278398)                            \
+  V(_List, ., ObjectArrayAllocate, 184405219)                                  \
+  V(_TypedList, _getInt8, ByteArrayBaseGetInt8, 187609847)                     \
+  V(_TypedList, _getUint8, ByteArrayBaseGetUint8, 1826086346)                  \
+  V(_TypedList, _getInt16, ByteArrayBaseGetInt16, 1174755987)                  \
+  V(_TypedList, _getUint16, ByteArrayBaseGetUint16, 1936358273)                \
+  V(_TypedList, _getInt32, ByteArrayBaseGetInt32, 1123951931)                  \
+  V(_TypedList, _getUint32, ByteArrayBaseGetUint32, 853172551)                 \
+  V(_TypedList, _getInt64, ByteArrayBaseGetInt64, 1115954619)                  \
+  V(_TypedList, _getFloat32, ByteArrayBaseGetFloat32, 165422183)               \
+  V(_TypedList, _getFloat64, ByteArrayBaseGetFloat64, 1564825450)              \
+  V(_TypedList, _getFloat32x4, ByteArrayBaseGetFloat32x4, 1123952315)          \
+  V(_TypedList, _getInt32x4, ByteArrayBaseGetInt32x4, 831892409)               \
+  V(_TypedList, _setInt8, ByteArrayBaseSetInt8, 2043203289)                    \
+  V(_TypedList, _setUint8, ByteArrayBaseSetUint8, 1759261408)                  \
+  V(_TypedList, _setInt16, ByteArrayBaseSetInt16, 267848339)                   \
+  V(_TypedList, _setUint16, ByteArrayBaseSetUint16, 350952121)                 \
+  V(_TypedList, _setInt32, ByteArrayBaseSetInt32, 1170619358)                  \
+  V(_TypedList, _setUint32, ByteArrayBaseSetUint32, 1325523969)                \
+  V(_TypedList, _setInt64, ByteArrayBaseSetInt64, 935451230)                   \
+  V(_TypedList, _setFloat32, ByteArrayBaseSetFloat32, 541136999)               \
+  V(_TypedList, _setFloat64, ByteArrayBaseSetFloat64, 365317124)               \
+  V(_TypedList, _setFloat32x4, ByteArrayBaseSetFloat32x4, 1766802707)          \
+  V(_TypedList, _setInt32x4, ByteArrayBaseSetInt32x4, 2075229300)              \
+  V(_StringBase, _interpolate, StringBaseInterpolate, 1597087225)              \
+  V(_IntegerImplementation, toDouble, IntegerToDouble, 150718448)              \
   V(_IntegerImplementation, _leftShiftWithMask32,                              \
-      IntegerLeftShiftWithMask32, 598958097)                                   \
-  V(_Double, truncateToDouble, DoubleTruncate, 2117801967)                     \
-  V(_Double, roundToDouble, DoubleRound, 2124216110)                           \
-  V(_Double, floorToDouble, DoubleFloor, 968600699)                            \
-  V(_Double, ceilToDouble, DoubleCeil, 1779929274)                             \
-  V(_Double, _modulo, DoubleMod, 1473971007)                                   \
-  V(_Double, _add, DoubleAdd, 1570715125)                                      \
-  V(_Double, _sub, DoubleSub, 1466395310)                                      \
-  V(_Double, _mul, DoubleMul, 546441193)                                       \
-  V(_Double, _div, DoubleDiv, 1201505037)                                      \
-  V(::, sin, MathSin, 1741396147)                                              \
-  V(::, cos, MathCos, 1951197905)                                              \
-  V(::, tan, MathTan, 982072809)                                               \
-  V(::, asin, MathAsin, 1651042633)                                            \
-  V(::, acos, MathAcos, 1139647090)                                            \
-  V(::, atan, MathAtan, 1668754384)                                            \
-  V(::, atan2, MathAtan2, 1931713076)                                          \
-  V(::, min, MathMin, 478627534)                                               \
-  V(::, max, MathMax, 212291192)                                               \
-  V(::, _doublePow, MathDoublePow, 1286501289)                                 \
-  V(Float32x4, Float32x4., Float32x4Constructor, 1413513587)                   \
-  V(Float32x4, Float32x4.zero, Float32x4Zero, 865663495)                       \
-  V(Float32x4, Float32x4.splat, Float32x4Splat, 964312836)                     \
-  V(Float32x4, Float32x4.fromInt32x4Bits, Float32x4FromInt32x4Bits, 688177588) \
-  V(Float32x4, Float32x4.fromFloat64x2, Float32x4FromFloat64x2, 1327692716)    \
-  V(_Float32x4, shuffle, Float32x4Shuffle, 1636488139)                         \
-  V(_Float32x4, shuffleMix, Float32x4ShuffleMix, 654814229)                    \
-  V(_Float32x4, get:signMask, Float32x4GetSignMask, 630880675)                 \
-  V(_Float32x4, _cmpequal, Float32x4Equal, 571062952)                          \
-  V(_Float32x4, _cmpgt, Float32x4GreaterThan, 1613543295)                      \
-  V(_Float32x4, _cmpgte, Float32x4GreaterThanOrEqual, 589402909)               \
-  V(_Float32x4, _cmplt, Float32x4LessThan, 1502332656)                         \
-  V(_Float32x4, _cmplte, Float32x4LessThanOrEqual, 1069848031)                 \
-  V(_Float32x4, _cmpnequal, Float32x4NotEqual, 1334574472)                     \
-  V(_Float32x4, _min, Float32x4Min, 2036349551)                                \
-  V(_Float32x4, _max, Float32x4Max, 571688115)                                 \
-  V(_Float32x4, _scale, Float32x4Scale, 1311297761)                            \
-  V(_Float32x4, _sqrt, Float32x4Sqrt, 1709659395)                              \
-  V(_Float32x4, _reciprocalSqrt, Float32x4ReciprocalSqrt, 2043980962)          \
-  V(_Float32x4, _reciprocal, Float32x4Reciprocal, 739405237)                   \
-  V(_Float32x4, _negate, Float32x4Negate, 445839777)                           \
-  V(_Float32x4, _abs, Float32x4Absolute, 1152777608)                           \
-  V(_Float32x4, _clamp, Float32x4Clamp, 410673744)                             \
-  V(_Float32x4, withX, Float32x4WithX, 1446546696)                             \
-  V(_Float32x4, withY, Float32x4WithY, 309844761)                              \
-  V(_Float32x4, withZ, Float32x4WithZ, 971921505)                              \
-  V(_Float32x4, withW, Float32x4WithW, 1759699726)                             \
-  V(Float64x2, Float64x2., Float64x2Constructor, 1047027504)                   \
-  V(Float64x2, Float64x2.zero, Float64x2Zero, 1208364703)                      \
-  V(Float64x2, Float64x2.splat, Float64x2Splat, 987392531)                     \
-  V(Float64x2, Float64x2.fromFloat32x4, Float64x2FromFloat32x4, 1547827778)    \
-  V(_Float64x2, get:x, Float64x2GetX, 261163258)                               \
-  V(_Float64x2, get:y, Float64x2GetY, 1942377050)                              \
-  V(_Float64x2, _negate, Float64x2Negate, 2133212774)                          \
-  V(_Float64x2, abs, Float64x2Abs, 1224776282)                                 \
-  V(_Float64x2, sqrt, Float64x2Sqrt, 1037569520)                               \
-  V(_Float64x2, get:signMask, Float64x2GetSignMask, 253055964)                 \
-  V(_Float64x2, scale, Float64x2Scale, 1199438744)                             \
-  V(_Float64x2, withX, Float64x2WithX, 1042725932)                             \
-  V(_Float64x2, withY, Float64x2WithY, 1496958947)                             \
-  V(_Float64x2, min, Float64x2Min, 485240583)                                  \
-  V(_Float64x2, max, Float64x2Max, 2146148204)                                 \
-  V(Int32x4, Int32x4., Int32x4Constructor, 323626792)                          \
-  V(Int32x4, Int32x4.bool, Int32x4BoolConstructor, 637206368)                  \
-  V(Int32x4, Int32x4.fromFloat32x4Bits, Int32x4FromFloat32x4Bits, 420618790)   \
-  V(_Int32x4, get:flagX, Int32x4GetFlagX, 1077674402)                          \
-  V(_Int32x4, get:flagY, Int32x4GetFlagY, 779279448)                           \
-  V(_Int32x4, get:flagZ, Int32x4GetFlagZ, 182031447)                           \
-  V(_Int32x4, get:flagW, Int32x4GetFlagW, 977794698)                           \
-  V(_Int32x4, get:signMask, Int32x4GetSignMask, 1929391078)                    \
-  V(_Int32x4, shuffle, Int32x4Shuffle, 1870018702)                             \
-  V(_Int32x4, shuffleMix, Int32x4ShuffleMix, 1024903172)                       \
-  V(_Int32x4, select, Int32x4Select, 1638081645)                               \
-  V(_Int32x4, withFlagX, Int32x4WithFlagX, 467852789)                          \
-  V(_Int32x4, withFlagY, Int32x4WithFlagY, 1903359978)                         \
-  V(_Int32x4, withFlagZ, Int32x4WithFlagZ, 862460960)                          \
-  V(_Int32x4, withFlagW, Int32x4WithFlagW, 1095242907)                         \
-  V(_Float32Array, [], Float32ArrayGetIndexed, 321832479)                      \
-  V(_Float32Array, []=, Float32ArraySetIndexed, 979306169)                     \
-  V(_Int8Array, [], Int8ArrayGetIndexed, 1390782783)                           \
-  V(_Int8Array, []=, Int8ArraySetIndexed, 1774152196)                          \
-  V(_Uint8ClampedArray, [], Uint8ClampedArrayGetIndexed, 1297457028)           \
-  V(_Uint8ClampedArray, []=, Uint8ClampedArraySetIndexed, 2018722539)          \
-  V(_ExternalUint8ClampedArray, [],                                            \
-      ExternalUint8ClampedArrayGetIndexed, 1871828532)                         \
-  V(_ExternalUint8ClampedArray, []=,                                           \
-      ExternalUint8ClampedArraySetIndexed, 1746834469)                         \
-  V(_Int16Array, [], Int16ArrayGetIndexed, 1699340532)                         \
-  V(_Int16Array, []=, Int16ArraySetIndexed, 799870496)                         \
-  V(_Uint16Array, [], Uint16ArrayGetIndexed, 452576118)                        \
-  V(_Uint16Array, []=, Uint16ArraySetIndexed, 1594961463)                      \
-  V(_Int32Array, [], Int32ArrayGetIndexed, 2052925823)                         \
-  V(_Int32Array, []=, Int32ArraySetIndexed, 504626978)                         \
-  V(_Int64Array, [], Int64ArrayGetIndexed, 297668331)                          \
-  V(_Int64Array, []=, Int64ArraySetIndexed, 36465128)                          \
-  V(_Float32x4Array, [], Float32x4ArrayGetIndexed, 35821240)                   \
-  V(_Float32x4Array, []=, Float32x4ArraySetIndexed, 428758949)                 \
-  V(_Int32x4Array, [], Int32x4ArrayGetIndexed, 1830534333)                     \
-  V(_Int32x4Array, []=, Int32x4ArraySetIndexed, 1631676655)                    \
-  V(_Float64x2Array, [], Float64x2ArrayGetIndexed, 1860837505)                 \
-  V(_Float64x2Array, []=, Float64x2ArraySetIndexed, 821269609)                 \
-  V(_Bigint, get:_neg, Bigint_getNeg, 1151633263)                              \
-  V(_Bigint, get:_used, Bigint_getUsed, 1308648707)                            \
-  V(_Bigint, get:_digits, Bigint_getDigits, 1408181836)                        \
-  V(_HashVMBase, get:_index, LinkedHashMap_getIndex, 1431607529)               \
-  V(_HashVMBase, set:_index, LinkedHashMap_setIndex, 2007926178)               \
-  V(_HashVMBase, get:_data, LinkedHashMap_getData, 958070909)                  \
-  V(_HashVMBase, set:_data, LinkedHashMap_setData, 1134236592)                 \
-  V(_HashVMBase, get:_usedData, LinkedHashMap_getUsedData, 421669312)          \
-  V(_HashVMBase, set:_usedData, LinkedHashMap_setUsedData, 1152062737)         \
-  V(_HashVMBase, get:_hashMask, LinkedHashMap_getHashMask, 969476186)          \
-  V(_HashVMBase, set:_hashMask, LinkedHashMap_setHashMask, 1781420082)         \
-  V(_HashVMBase, get:_deletedKeys, LinkedHashMap_getDeletedKeys, 63633039)     \
-  V(_HashVMBase, set:_deletedKeys, LinkedHashMap_setDeletedKeys, 2079107858)   \
+      IntegerLeftShiftWithMask32, 1634465017)                                  \
+  V(_Double, truncateToDouble, DoubleTruncate, 791143891)                      \
+  V(_Double, roundToDouble, DoubleRound, 797558034)                            \
+  V(_Double, floorToDouble, DoubleFloor, 1789426271)                           \
+  V(_Double, ceilToDouble, DoubleCeil, 453271198)                              \
+  V(_Double, _modulo, DoubleMod, 1093862165)                                   \
+  V(_Double, _add, DoubleAdd, 1190606283)                                      \
+  V(_Double, _sub, DoubleSub, 1086286468)                                      \
+  V(_Double, _mul, DoubleMul, 166332351)                                       \
+  V(_Double, _div, DoubleDiv, 821396195)                                       \
+  V(::, sin, MathSin, 939048573)                                               \
+  V(::, cos, MathCos, 1148850331)                                              \
+  V(::, tan, MathTan, 179725235)                                               \
+  V(::, asin, MathAsin, 848695059)                                             \
+  V(::, acos, MathAcos, 337299516)                                             \
+  V(::, atan, MathAtan, 866406810)                                             \
+  V(::, atan2, MathAtan2, 1901969510)                                          \
+  V(::, min, MathMin, 1115051548)                                              \
+  V(::, max, MathMax, 1410473322)                                              \
+  V(::, _doublePow, MathDoublePow, 562154128)                                  \
+  V(Float32x4, Float32x4., Float32x4Constructor, 1849420944)                   \
+  V(Float32x4, Float32x4.zero, Float32x4Zero, 762161262)                       \
+  V(Float32x4, Float32x4.splat, Float32x4Splat, 255855286)                     \
+  V(Float32x4, Float32x4.fromInt32x4Bits, Float32x4FromInt32x4Bits, 1718571366)\
+  V(Float32x4, Float32x4.fromFloat64x2, Float32x4FromFloat64x2, 1458098858)    \
+  V(_Float32x4, shuffle, Float32x4Shuffle, 2015957023)                         \
+  V(_Float32x4, shuffleMix, Float32x4ShuffleMix, 1099087979)                   \
+  V(_Float32x4, get:signMask, Float32x4GetSignMask, 487049875)                 \
+  V(_Float32x4, _cmpequal, Float32x4Equal, 1069901308)                         \
+  V(_Float32x4, _cmpgt, Float32x4GreaterThan, 2112381651)                      \
+  V(_Float32x4, _cmpgte, Float32x4GreaterThanOrEqual, 1088241265)              \
+  V(_Float32x4, _cmplt, Float32x4LessThan, 2001171012)                         \
+  V(_Float32x4, _cmplte, Float32x4LessThanOrEqual, 1568686387)                 \
+  V(_Float32x4, _cmpnequal, Float32x4NotEqual, 1833412828)                     \
+  V(_Float32x4, _min, Float32x4Min, 1194113943)                                \
+  V(_Float32x4, _max, Float32x4Max, 1876936155)                                \
+  V(_Float32x4, _scale, Float32x4Scale, 1176743640)                            \
+  V(_Float32x4, _sqrt, Float32x4Sqrt, 526238610)                               \
+  V(_Float32x4, _reciprocalSqrt, Float32x4ReciprocalSqrt, 860560177)           \
+  V(_Float32x4, _reciprocal, Float32x4Reciprocal, 1703468100)                  \
+  V(_Float32x4, _negate, Float32x4Negate, 1409902640)                          \
+  V(_Float32x4, _abs, Float32x4Absolute, 2116840471)                           \
+  V(_Float32x4, _clamp, Float32x4Clamp, 1789892357)                            \
+  V(_Float32x4, withX, Float32x4WithX, 1311992575)                             \
+  V(_Float32x4, withY, Float32x4WithY, 175290640)                              \
+  V(_Float32x4, withZ, Float32x4WithZ, 837367384)                              \
+  V(_Float32x4, withW, Float32x4WithW, 1625145605)                             \
+  V(Float64x2, Float64x2., Float64x2Constructor, 1428850802)                   \
+  V(Float64x2, Float64x2.zero, Float64x2Zero, 29170676)                        \
+  V(Float64x2, Float64x2.splat, Float64x2Splat, 1077183856)                    \
+  V(Float64x2, Float64x2.fromFloat32x4, Float64x2FromFloat32x4, 1752000980)    \
+  V(_Float64x2, get:x, Float64x2GetX, 1488958362)                              \
+  V(_Float64x2, get:y, Float64x2GetY, 1022688506)                              \
+  V(_Float64x2, _negate, Float64x2Negate, 960840275)                           \
+  V(_Float64x2, abs, Float64x2Abs, 52403783)                                   \
+  V(_Float64x2, sqrt, Float64x2Sqrt, 2012680669)                               \
+  V(_Float64x2, get:signMask, Float64x2GetSignMask, 668856717)                 \
+  V(_Float64x2, scale, Float64x2Scale, 646122081)                              \
+  V(_Float64x2, withX, Float64x2WithX, 489409269)                              \
+  V(_Float64x2, withY, Float64x2WithY, 943642284)                              \
+  V(_Float64x2, min, Float64x2Min, 685235702)                                  \
+  V(_Float64x2, max, Float64x2Max, 198659675)                                  \
+  V(Int32x4, Int32x4., Int32x4Constructor, 80862812)                           \
+  V(Int32x4, Int32x4.bool, Int32x4BoolConstructor, 1949580252)                 \
+  V(Int32x4, Int32x4.fromFloat32x4Bits, Int32x4FromFloat32x4Bits, 1611205288)  \
+  V(_Int32x4, get:flagX, Int32x4GetFlagX, 1446544324)                          \
+  V(_Int32x4, get:flagY, Int32x4GetFlagY, 1148149370)                          \
+  V(_Int32x4, get:flagZ, Int32x4GetFlagZ, 550901369)                           \
+  V(_Int32x4, get:flagW, Int32x4GetFlagW, 1346664620)                          \
+  V(_Int32x4, get:signMask, Int32x4GetSignMask, 740215269)                     \
+  V(_Int32x4, shuffle, Int32x4Shuffle, 549194518)                              \
+  V(_Int32x4, shuffleMix, Int32x4ShuffleMix, 1550866145)                       \
+  V(_Int32x4, select, Int32x4Select, 614943686)                                \
+  V(_Int32x4, withFlagX, Int32x4WithFlagX, 250974159)                          \
+  V(_Int32x4, withFlagY, Int32x4WithFlagY, 1686481348)                         \
+  V(_Int32x4, withFlagZ, Int32x4WithFlagZ, 645582330)                          \
+  V(_Int32x4, withFlagW, Int32x4WithFlagW, 878364277)                          \
+  V(_Float32Array, [], Float32ArrayGetIndexed, 1002307136)                     \
+  V(_Float32Array, []=, Float32ArraySetIndexed, 279546769)                     \
+  V(_Int8Array, [], Int8ArrayGetIndexed, 1141846285)                           \
+  V(_Int8Array, []=, Int8ArraySetIndexed, 1486839324)                          \
+  V(_Uint8ClampedArray, [], Uint8ClampedArrayGetIndexed, 513704632)            \
+  V(_Uint8ClampedArray, []=, Uint8ClampedArraySetIndexed, 1015846567)          \
+  V(_ExternalUint8ClampedArray, [], ExternalUint8ClampedArrayGetIndexed,       \
+    513704632)                                                                 \
+  V(_ExternalUint8ClampedArray, []=, ExternalUint8ClampedArraySetIndexed,      \
+    1015846567)                                                                \
+  V(_Int16Array, [], Int16ArrayGetIndexed, 1826359619)                         \
+  V(_Int16Array, []=, Int16ArraySetIndexed, 1108689116)                        \
+  V(_Uint16Array, [], Uint16ArrayGetIndexed, 118958722)                        \
+  V(_Uint16Array, []=, Uint16ArraySetIndexed, 658824450)                       \
+  V(_Int32Array, [], Int32ArrayGetIndexed, 681203163)                          \
+  V(_Int32Array, []=, Int32ArraySetIndexed, 1786886245)                        \
+  V(_Int64Array, [], Int64ArrayGetIndexed, 1883155004)                         \
+  V(_Int64Array, []=, Int64ArraySetIndexed, 905815059)                         \
+  V(_Float32x4Array, [], Float32x4ArrayGetIndexed, 694822356)                  \
+  V(_Float32x4Array, []=, Float32x4ArraySetIndexed, 1166109127)                \
+  V(_Int32x4Array, [], Int32x4ArrayGetIndexed, 668249259)                      \
+  V(_Int32x4Array, []=, Int32x4ArraySetIndexed, 654739449)                     \
+  V(_Float64x2Array, [], Float64x2ArrayGetIndexed, 196472005)                  \
+  V(_Float64x2Array, []=, Float64x2ArraySetIndexed, 1421858500)                \
+  V(_Bigint, get:_neg, Bigint_getNeg, 1681019799)                              \
+  V(_Bigint, get:_used, Bigint_getUsed, 1439136438)                            \
+  V(_Bigint, get:_digits, Bigint_getDigits, 769722770)                         \
+  V(_HashVMBase, get:_index, LinkedHashMap_getIndex, 2048715833)               \
+  V(_HashVMBase, set:_index, LinkedHashMap_setIndex, 1882796480)               \
+  V(_HashVMBase, get:_data, LinkedHashMap_getData, 942992497)                  \
+  V(_HashVMBase, set:_data, LinkedHashMap_setData, 1410623019)                 \
+  V(_HashVMBase, get:_usedData, LinkedHashMap_getUsedData, 1698421819)         \
+  V(_HashVMBase, set:_usedData, LinkedHashMap_setUsedData, 1858754514)         \
+  V(_HashVMBase, get:_hashMask, LinkedHashMap_getHashMask, 98745045)           \
+  V(_HashVMBase, set:_hashMask, LinkedHashMap_setHashMask, 340628211)          \
+  V(_HashVMBase, get:_deletedKeys, LinkedHashMap_getDeletedKeys, 1340385546)   \
+  V(_HashVMBase, set:_deletedKeys, LinkedHashMap_setDeletedKeys, 638315987)    \
 
 
 // List of intrinsics:
 // (class-name, function-name, intrinsification method, fingerprint).
 #define CORE_LIB_INTRINSIC_LIST(V)                                             \
-  V(_Smi, ~, Smi_bitNegate, 221883538)                                         \
-  V(_Smi, get:bitLength, Smi_bitLength, 870075661)                             \
-  V(_Bigint, _lsh, Bigint_lsh, 1457834861)                                     \
-  V(_Bigint, _rsh, Bigint_rsh, 1619318930)                                     \
-  V(_Bigint, _absAdd, Bigint_absAdd, 1029882563)                               \
-  V(_Bigint, _absSub, Bigint_absSub, 1407667556)                               \
-  V(_Bigint, _mulAdd, Bigint_mulAdd, 1408994809)                               \
-  V(_Bigint, _sqrAdd, Bigint_sqrAdd, 2025116181)                               \
-  V(_Bigint, _estQuotientDigit, Bigint_estQuotientDigit, 919247767)            \
-  V(_Montgomery, _mulMod, Montgomery_mulMod, 401580778)                        \
-  V(_Double, >, Double_greaterThan, 1329424300)                                \
-  V(_Double, >=, Double_greaterEqualThan, 805805707)                           \
-  V(_Double, <, Double_lessThan, 1504529159)                                   \
-  V(_Double, <=, Double_lessEqualThan, 1650247787)                             \
-  V(_Double, ==, Double_equal, 1107327662)                                     \
-  V(_Double, +, Double_add, 957499569)                                         \
-  V(_Double, -, Double_sub, 788608394)                                         \
-  V(_Double, *, Double_mul, 645729895)                                         \
-  V(_Double, /, Double_div, 1249186273)                                        \
-  V(_Double, get:isNaN, Double_getIsNaN, 843169197)                            \
-  V(_Double, get:isNegative, Double_getIsNegative, 1637994744)                 \
-  V(_Double, _mulFromInteger, Double_mulFromInteger, 63390017)                 \
-  V(_Double, .fromInteger, DoubleFromInteger, 213717920)                       \
-  V(_List, []=, ObjectArraySetIndexed, 527521746)                              \
-  V(_GrowableList, .withData, GrowableArray_Allocate, 2094352700)              \
-  V(_GrowableList, add, GrowableArray_add, 1675959698)                         \
-  V(_JSSyntaxRegExp, _ExecuteMatch, JSRegExp_ExecuteMatch, 1711509198)         \
-  V(Object, ==, ObjectEquals, 409406570)                                       \
-  V(Object, get:runtimeType, ObjectRuntimeType, 2076963579)                    \
-  V(_StringBase, get:hashCode, String_getHashCode, 2103025405)                 \
-  V(_StringBase, get:isEmpty, StringBaseIsEmpty, 780870414)                    \
-  V(_StringBase, codeUnitAt, StringBaseCodeUnitAt, 397735324)                  \
-  V(_StringBase, _substringMatches, StringBaseSubstringMatches, 347814979)     \
-  V(_StringBase, [], StringBaseCharAt, 408544820)                              \
-  V(_OneByteString, get:hashCode, OneByteString_getHashCode, 1111957093)       \
+  V(_Smi, ~, Smi_bitNegate, 1673522705)                                        \
+  V(_Smi, get:bitLength, Smi_bitLength, 632480332)                             \
+  V(_Bigint, _lsh, Bigint_lsh, 834311957)                                      \
+  V(_Bigint, _rsh, Bigint_rsh, 333337658)                                      \
+  V(_Bigint, _absAdd, Bigint_absAdd, 473436659)                                \
+  V(_Bigint, _absSub, Bigint_absSub, 1018678324)                               \
+  V(_Bigint, _mulAdd, Bigint_mulAdd, 571005736)                                \
+  V(_Bigint, _sqrAdd, Bigint_sqrAdd, 372896038)                                \
+  V(_Bigint, _estQuotientDigit, Bigint_estQuotientDigit, 540033329)            \
+  V(_Montgomery, _mulMod, Montgomery_mulMod, 118781828)                        \
+  V(_Double, >, Double_greaterThan, 1413076759)                                \
+  V(_Double, >=, Double_greaterEqualThan, 1815180096)                          \
+  V(_Double, <, Double_lessThan, 652059836)                                    \
+  V(_Double, <=, Double_lessEqualThan, 512138528)                              \
+  V(_Double, ==, Double_equal, 752327620)                                      \
+  V(_Double, +, Double_add, 854024064)                                         \
+  V(_Double, -, Double_sub, 685132889)                                         \
+  V(_Double, *, Double_mul, 542254390)                                         \
+  V(_Double, /, Double_div, 1145710768)                                        \
+  V(_Double, get:isNaN, Double_getIsNaN, 184085483)                            \
+  V(_Double, get:isNegative, Double_getIsNegative, 978911030)                  \
+  V(_Double, _mulFromInteger, Double_mulFromInteger, 543831179)                \
+  V(_Double, .fromInteger, DoubleFromInteger, 1453449234)                      \
+  V(_List, []=, ObjectArraySetIndexed, 886228780)                              \
+  V(_GrowableList, .withData, GrowableArray_Allocate, 131424500)               \
+  V(_GrowableList, add, GrowableArray_add, 242296201)                          \
+  V(_JSSyntaxRegExp, _ExecuteMatch, JSRegExp_ExecuteMatch, 1490503678)         \
+  V(Object, ==, ObjectEquals, 291909336)                                       \
+  V(Object, get:runtimeType, ObjectRuntimeType, 15188587)                      \
+  V(_StringBase, get:hashCode, String_getHashCode, 2026040200)                 \
+  V(_StringBase, get:isEmpty, StringBaseIsEmpty, 1958879178)                   \
+  V(_StringBase, codeUnitAt, StringBaseCodeUnitAt, 1436590579)                 \
+  V(_StringBase, _substringMatches, StringBaseSubstringMatches, 1548648995)    \
+  V(_StringBase, [], StringBaseCharAt, 754527301)                              \
+  V(_OneByteString, get:hashCode, OneByteString_getHashCode, 2026040200)       \
   V(_OneByteString, _substringUncheckedNative,                                 \
-      OneByteString_substringUnchecked, 1584757277)                            \
-  V(_OneByteString, _setAt, OneByteStringSetAt, 1927993207)                    \
-  V(_OneByteString, _allocate, OneByteString_allocate, 1248050114)             \
-  V(_OneByteString, ==, OneByteString_equality, 1151307249)                    \
-  V(_TwoByteString, ==, TwoByteString_equality, 375409915)                     \
+    OneByteString_substringUnchecked, 2063670029)                              \
+  V(_OneByteString, _setAt, OneByteStringSetAt, 929822971)                     \
+  V(_OneByteString, _allocate, OneByteString_allocate, 1737851380)             \
+  V(_OneByteString, ==, OneByteString_equality, 1062844160)                    \
+  V(_TwoByteString, ==, TwoByteString_equality, 1062844160)                    \
 
 
 #define CORE_INTEGER_LIB_INTRINSIC_LIST(V)                                     \
-  V(_IntegerImplementation, _addFromInteger, Integer_addFromInteger,           \
-    438687793)                                                                 \
-  V(_IntegerImplementation, +, Integer_add, 6890122)                           \
-  V(_IntegerImplementation, _subFromInteger, Integer_subFromInteger,           \
-    562800077)                                                                 \
-  V(_IntegerImplementation, -, Integer_sub, 1325066635)                        \
+  V(_IntegerImplementation, _addFromInteger, Integer_addFromInteger, 298045644)\
+  V(_IntegerImplementation, +, Integer_add, 364498398)                         \
+  V(_IntegerImplementation, _subFromInteger, Integer_subFromInteger, 422157928)\
+  V(_IntegerImplementation, -, Integer_sub, 1682674911)                        \
   V(_IntegerImplementation, _mulFromInteger, Integer_mulFromInteger,           \
-    67891834)                                                                  \
-  V(_IntegerImplementation, *, Integer_mul, 1293507180)                        \
+    2074733333)                                                                \
+  V(_IntegerImplementation, *, Integer_mul, 1651115456)                        \
   V(_IntegerImplementation, _moduloFromInteger, Integer_moduloFromInteger,     \
-    93478264)                                                                  \
-  V(_IntegerImplementation, ~/, Integer_truncDivide, 1401079912)               \
-  V(_IntegerImplementation, unary-, Integer_negate, 1992904169)                \
-  V(_IntegerImplementation, _bitAndFromInteger,                                \
-    Integer_bitAndFromInteger, 504496713)                                      \
-  V(_IntegerImplementation, &, Integer_bitAnd, 154523381)                      \
-  V(_IntegerImplementation, _bitOrFromInteger,                                 \
-    Integer_bitOrFromInteger, 1763728073)                                      \
-  V(_IntegerImplementation, |, Integer_bitOr, 979400883)                       \
-  V(_IntegerImplementation, _bitXorFromInteger,                                \
-    Integer_bitXorFromInteger, 281425907)                                      \
-  V(_IntegerImplementation, ^, Integer_bitXor, 1753100628)                     \
-  V(_IntegerImplementation,                                                    \
-    _greaterThanFromInteger,                                                   \
-    Integer_greaterThanFromInt, 787426822)                                     \
-  V(_IntegerImplementation, >, Integer_greaterThan, 871319346)                 \
-  V(_IntegerImplementation, ==, Integer_equal, 150126631)                      \
+    2100319763)                                                                \
+  V(_IntegerImplementation, ~/, Integer_truncDivide, 108494012)                \
+  V(_IntegerImplementation, unary-, Integer_negate, 1507648892)                \
+  V(_IntegerImplementation, _bitAndFromInteger, Integer_bitAndFromInteger,     \
+    363854564)                                                                 \
+  V(_IntegerImplementation, &, Integer_bitAnd, 286231290)                      \
+  V(_IntegerImplementation, _bitOrFromInteger, Integer_bitOrFromInteger,       \
+    1623085924)                                                                \
+  V(_IntegerImplementation, |, Integer_bitOr, 1111108792)                      \
+  V(_IntegerImplementation, _bitXorFromInteger, Integer_bitXorFromInteger,     \
+    140783758)                                                                 \
+  V(_IntegerImplementation, ^, Integer_bitXor, 1884808537)                     \
+  V(_IntegerImplementation, _greaterThanFromInteger,                           \
+    Integer_greaterThanFromInt, 814932166)                                     \
+  V(_IntegerImplementation, >, Integer_greaterThan, 293890061)                 \
+  V(_IntegerImplementation, ==, Integer_equal, 4489308)                        \
   V(_IntegerImplementation, _equalToInteger, Integer_equalToInteger,           \
-    1790821042)                                                                \
-  V(_IntegerImplementation, <, Integer_lessThan, 1997184951)                   \
-  V(_IntegerImplementation, <=, Integer_lessEqualThan, 909274395)              \
-  V(_IntegerImplementation, >=, Integer_greaterEqualThan, 64832315)            \
-  V(_IntegerImplementation, <<, Integer_shl, 162043543)                        \
-  V(_IntegerImplementation, >>, Integer_sar, 2140866840)                       \
-  V(_Double, toInt, DoubleToInteger, 1547535151)
+    1818326386)                                                                \
+  V(_IntegerImplementation, <, Integer_lessThan, 652059836)                    \
+  V(_IntegerImplementation, <=, Integer_lessEqualThan, 512138528)              \
+  V(_IntegerImplementation, >=, Integer_greaterEqualThan, 1815180096)          \
+  V(_IntegerImplementation, <<, Integer_shl, 293751452)                        \
+  V(_IntegerImplementation, >>, Integer_sar, 125091101)                        \
+  V(_Double, toInt, DoubleToInteger, 653210699)
 
 
 #define MATH_LIB_INTRINSIC_LIST(V)                                             \
-  V(::, sqrt, MathSqrt, 101545548)                                             \
-  V(_Random, _nextState, Random_nextState, 170407315)                          \
+  V(::, sqrt, MathSqrt, 1446681622)                                            \
+  V(_Random, _nextState, Random_nextState, 1241583299)                         \
 
 
 #define TYPED_DATA_LIB_INTRINSIC_LIST(V)                                       \
-  V(_Int8Array, _new, TypedData_Int8Array_new, 362764911)                      \
-  V(_Uint8Array, _new, TypedData_Uint8Array_new, 1232298852)                   \
-  V(_Uint8ClampedArray, _new, TypedData_Uint8ClampedArray_new, 2086529408)     \
-  V(_Int16Array, _new, TypedData_Int16Array_new, 1092174107)                   \
-  V(_Uint16Array, _new, TypedData_Uint16Array_new, 1549613141)                 \
-  V(_Int32Array, _new, TypedData_Int32Array_new, 937960140)                    \
-  V(_Uint32Array, _new, TypedData_Uint32Array_new, 1370423225)                 \
-  V(_Int64Array, _new, TypedData_Int64Array_new, 512135010)                    \
-  V(_Uint64Array, _new, TypedData_Uint64Array_new, 847951795)                  \
-  V(_Float32Array, _new, TypedData_Float32Array_new, 1937854220)               \
-  V(_Float64Array, _new, TypedData_Float64Array_new, 2005472426)               \
-  V(_Float32x4Array, _new, TypedData_Float32x4Array_new, 1956756158)           \
-  V(_Int32x4Array, _new, TypedData_Int32x4Array_new, 1856474973)               \
-  V(_Float64x2Array, _new, TypedData_Float64x2Array_new, 719608172)            \
-  V(_Int8Array, ., TypedData_Int8Array_factory, 439914696)                     \
-  V(_Uint8Array, ., TypedData_Uint8Array_factory, 1442599030)                  \
-  V(_Uint8ClampedArray, ., TypedData_Uint8ClampedArray_factory, 1320015159)    \
-  V(_Int16Array, ., TypedData_Int16Array_factory, 2132591678)                  \
-  V(_Uint16Array, ., TypedData_Uint16Array_factory, 1704816032)                \
-  V(_Int32Array, ., TypedData_Int32Array_factory, 1115045147)                  \
-  V(_Uint32Array, ., TypedData_Uint32Array_factory, 1385852190)                \
-  V(_Int64Array, ., TypedData_Int64Array_factory, 1193438555)                  \
-  V(_Uint64Array, ., TypedData_Uint64Array_factory, 410766246)                 \
-  V(_Float32Array, ., TypedData_Float32Array_factory, 1194249144)              \
-  V(_Float64Array, ., TypedData_Float64Array_factory, 1430631000)              \
-  V(_Float32x4Array, ., TypedData_Float32x4Array_factory, 158753569)           \
-  V(_Int32x4Array, ., TypedData_Int32x4Array_factory, 1189213641)              \
-  V(_Float64x2Array, ., TypedData_Float64x2Array_factory, 1699696799)          \
+  V(_Int8Array, _new, TypedData_Int8Array_new, 1025382728)                     \
+  V(_Uint8Array, _new, TypedData_Uint8Array_new, 1772090315)                   \
+  V(_Uint8ClampedArray, _new, TypedData_Uint8ClampedArray_new, 1817995920)     \
+  V(_Int16Array, _new, TypedData_Int16Array_new, 857482727)                    \
+  V(_Uint16Array, _new, TypedData_Uint16Array_new, 224498043)                  \
+  V(_Int32Array, _new, TypedData_Int32Array_new, 662785062)                    \
+  V(_Uint32Array, _new, TypedData_Uint32Array_new, 457777042)                  \
+  V(_Int64Array, _new, TypedData_Int64Array_new, 11424776)                     \
+  V(_Uint64Array, _new, TypedData_Uint64Array_new, 580841705)                  \
+  V(_Float32Array, _new, TypedData_Float32Array_new, 141243383)                \
+  V(_Float64Array, _new, TypedData_Float64Array_new, 2054234881)               \
+  V(_Float32x4Array, _new, TypedData_Float32x4Array_new, 1277009760)           \
+  V(_Int32x4Array, _new, TypedData_Int32x4Array_new, 366994774)                \
+  V(_Float64x2Array, _new, TypedData_Float64x2Array_new, 134695262)            \
+  V(_Int8Array, ., TypedData_Int8Array_factory, 484088513)                     \
+  V(_Uint8Array, ., TypedData_Uint8Array_factory, 1830561671)                  \
+  V(_Uint8ClampedArray, ., TypedData_Uint8ClampedArray_factory, 980532456)     \
+  V(_Int16Array, ., TypedData_Int16Array_factory, 2095566414)                  \
+  V(_Uint16Array, ., TypedData_Uint16Array_factory, 248627537)                 \
+  V(_Int32Array, ., TypedData_Int32Array_factory, 836050202)                   \
+  V(_Uint32Array, ., TypedData_Uint32Array_factory, 102123815)                 \
+  V(_Int64Array, ., TypedData_Int64Array_factory, 1820730838)                  \
+  V(_Uint64Array, ., TypedData_Uint64Array_factory, 1668399825)                \
+  V(_Float32Array, ., TypedData_Float32Array_factory, 307228626)               \
+  V(_Float64Array, ., TypedData_Float64Array_factory, 1700923139)              \
+  V(_Float32x4Array, ., TypedData_Float32x4Array_factory, 1083909924)          \
+  V(_Int32x4Array, ., TypedData_Int32x4Array_factory, 803703492)               \
+  V(_Float64x2Array, ., TypedData_Float64x2Array_factory, 944719167)           \
 
 #define GRAPH_TYPED_DATA_INTRINSICS_LIST(V) \
-  V(_Uint8Array, [], Uint8ArrayGetIndexed, 579862489)                          \
-  V(_Uint8Array, []=, Uint8ArraySetIndexed, 447309008)                         \
-  V(_ExternalUint8Array, [], ExternalUint8ArrayGetIndexed, 1293647140)         \
-  V(_ExternalUint8Array, []=, ExternalUint8ArraySetIndexed, 1593599192)        \
-  V(_Uint32Array, [], Uint32ArrayGetIndexed, 1034114777)                       \
-  V(_Uint32Array, []=, Uint32ArraySetIndexed, 918159348)                       \
-  V(_Float64Array, []=, Float64ArraySetIndexed, 887301703)                     \
-  V(_Float64Array, [], Float64ArrayGetIndexed, 1959896670)                     \
-  V(_TypedList, get:length, TypedDataLength, 522684521)                        \
-  V(_Float32x4, get:x, Float32x4ShuffleX, 384969722)                           \
-  V(_Float32x4, get:y, Float32x4ShuffleY, 1398121942)                          \
-  V(_Float32x4, get:z, Float32x4ShuffleZ, 1178175605)                          \
-  V(_Float32x4, get:w, Float32x4ShuffleW, 480951003)                           \
-  V(_Float32x4, _mul, Float32x4Mul, 1703784673)                                \
-  V(_Float32x4, _sub, Float32x4Sub, 1302598822)                                \
-  V(_Float32x4, _add, Float32x4Add, 182344215)                                 \
+  V(_Uint8Array, [], Uint8ArrayGetIndexed, 513704632)                          \
+  V(_Uint8Array, []=, Uint8ArraySetIndexed, 2123520783)                        \
+  V(_ExternalUint8Array, [], ExternalUint8ArrayGetIndexed, 513704632)          \
+  V(_ExternalUint8Array, []=, ExternalUint8ArraySetIndexed, 2123520783)        \
+  V(_Uint32Array, [], Uint32ArrayGetIndexed, 1179675338)                       \
+  V(_Uint32Array, []=, Uint32ArraySetIndexed, 1455695417)                      \
+  V(_Float64Array, []=, Float64ArraySetIndexed, 1929239576)                    \
+  V(_Float64Array, [], Float64ArrayGetIndexed, 816943529)                      \
+  V(_TypedList, get:length, TypedDataLength, 546364442)                        \
+  V(_Float32x4, get:x, Float32x4ShuffleX, 1674625343)                          \
+  V(_Float32x4, get:y, Float32x4ShuffleY, 540293915)                           \
+  V(_Float32x4, get:z, Float32x4ShuffleZ, 320347578)                           \
+  V(_Float32x4, get:w, Float32x4ShuffleW, 1770606624)                          \
+  V(_Float32x4, _mul, Float32x4Mul, 861549065)                                 \
+  V(_Float32x4, _sub, Float32x4Sub, 460363214)                                 \
+  V(_Float32x4, _add, Float32x4Add, 1487592255)                                \
 
 #define GRAPH_CORE_INTRINSICS_LIST(V)                                          \
-  V(_List, get:length, ObjectArrayLength, 1181471893)                          \
-  V(_List, [], ObjectArrayGetIndexed, 1839430267)                              \
-  V(_ImmutableList, get:length, ImmutableArrayLength, 275036891)               \
-  V(_ImmutableList, [], ImmutableArrayGetIndexed, 886511484)                   \
-  V(_GrowableList, get:length, GrowableArrayLength, 778624271)                 \
-  V(_GrowableList, get:_capacity, GrowableArrayCapacity, 555259239)            \
-  V(_GrowableList, _setData, GrowableArraySetData, 508234257)                  \
-  V(_GrowableList, _setLength, GrowableArraySetLength, 618179695)              \
-  V(_GrowableList, [], GrowableArrayGetIndexed, 1962926024)                    \
-  V(_GrowableList, []=, GrowableArraySetIndexed, 457344024)                    \
-  V(_StringBase, get:length, StringBaseLength, 784518792)                      \
-  V(_Double, unary-, DoubleFlipSignBit, 2107492213)
+  V(_List, get:length, ObjectArrayLength, 630471378)                           \
+  V(_List, [], ObjectArrayGetIndexed, 360400496)                               \
+  V(_ImmutableList, get:length, ImmutableArrayLength, 630471378)               \
+  V(_ImmutableList, [], ImmutableArrayGetIndexed, 360400496)                   \
+  V(_GrowableList, get:length, GrowableArrayLength, 417111542)                 \
+  V(_GrowableList, get:_capacity, GrowableArrayCapacity, 193746510)            \
+  V(_GrowableList, _setData, GrowableArraySetData, 1496536873)                 \
+  V(_GrowableList, _setLength, GrowableArraySetLength, 32203572)               \
+  V(_GrowableList, [], GrowableArrayGetIndexed, 1957529650)                    \
+  V(_GrowableList, []=, GrowableArraySetIndexed, 225246870)                    \
+  V(_StringBase, get:length, StringBaseLength, 707533587)                      \
+  V(_Double, unary-, DoubleFlipSignBit, 1783281169)
 
 #define GRAPH_INTRINSICS_LIST(V)                                               \
   GRAPH_CORE_INTRINSICS_LIST(V)                                                \
   GRAPH_TYPED_DATA_INTRINSICS_LIST(V)                                          \
 
 #define DEVELOPER_LIB_INTRINSIC_LIST(V)                                        \
-  V(_UserTag, makeCurrent, UserTag_makeCurrent, 788201614)                     \
-  V(::, _getDefaultTag, UserTag_defaultTag, 1080704381)                        \
-  V(::, _getCurrentTag, Profiler_getCurrentTag, 2048029229)                    \
+  V(_UserTag, makeCurrent, UserTag_makeCurrent, 187721469)                     \
+  V(::, _getDefaultTag, UserTag_defaultTag, 1872263331)                        \
+  V(::, _getCurrentTag, Profiler_getCurrentTag, 692104531)                     \
 
 #define ALL_INTRINSICS_NO_INTEGER_LIB_LIST(V)                                  \
   CORE_LIB_INTRINSIC_LIST(V)                                                   \
@@ -336,149 +333,149 @@
 
 // A list of core function that should always be inlined.
 #define INLINE_WHITE_LIST(V)                                                   \
-  V(Object, ==, ObjectEquals, 409406570)                                       \
-  V(_List, get:length, ObjectArrayLength, 1181471893)                          \
-  V(_ImmutableList, get:length, ImmutableArrayLength, 275036891)               \
-  V(_TypedList, get:length, TypedDataLength, 522684521)                        \
-  V(_GrowableList, get:length, GrowableArrayLength, 778624271)                 \
-  V(_GrowableList, add, GrowableListAdd, 1675959698)                           \
-  V(_GrowableList, removeLast, GrowableListRemoveLast, 1687341910)             \
-  V(_StringBase, get:length, StringBaseLength, 784518792)                      \
-  V(ListIterator, moveNext, ListIteratorMoveNext, 1698922708)                  \
-  V(_FixedSizeArrayIterator, moveNext, FixedListIteratorMoveNext, 53548649)    \
-  V(_GrowableList, get:iterator, GrowableArrayIterator, 830391682)             \
-  V(_GrowableList, forEach, GrowableArrayForEach, 792224678)                   \
-  V(_List, ., ObjectArrayAllocate, 850375012)                                  \
-  V(_List, [], ObjectArrayGetIndexed, 1839430267)                              \
-  V(_List, []=, ObjectArraySetIndexed, 527521746)                              \
-  V(ListMixin, get:isEmpty, ListMixinIsEmpty, 40656674)                        \
-  V(_List, get:iterator, ObjectArrayIterator, 1623553799)                      \
-  V(_List, forEach, ObjectArrayForEach, 1840334181)                            \
-  V(_List, _slice, ObjectArraySlice, 1370223553)                               \
-  V(_ImmutableList, get:iterator, ImmutableArrayIterator, 1527026181)          \
-  V(_ImmutableList, forEach, ImmutableArrayForEach, 1311466789)                \
-  V(_ImmutableList, [], ImmutableArrayGetIndexed, 886511484)                   \
-  V(_GrowableList, [], GrowableArrayGetIndexed, 1962926024)                    \
-  V(_GrowableList, []=, GrowableArraySetIndexed, 457344024)                    \
-  V(_Float32Array, [], Float32ArrayGetIndexed, 321832479)                      \
-  V(_Float32Array, []=, Float32ArraySetIndexed, 979306169)                     \
-  V(_Float64Array, [], Float64ArrayGetIndexed, 1959896670)                     \
-  V(_Float64Array, []=, Float64ArraySetIndexed, 887301703)                     \
-  V(_Int8Array, [], Int8ArrayGetIndexed, 1390782783)                           \
-  V(_Int8Array, []=, Int8ArraySetIndexed, 1774152196)                          \
-  V(_Uint8Array, [], Uint8ArrayGetIndexed, 579862489)                          \
-  V(_Uint8Array, []=, Uint8ArraySetIndexed, 447309008)                         \
-  V(_Uint8ClampedArray, [], Uint8ClampedArrayGetIndexed, 1297457028)           \
-  V(_Uint8ClampedArray, []=, Uint8ClampedArraySetIndexed, 2018722539)          \
-  V(_Uint16Array, [], Uint16ArrayGetIndexed, 452576118)                        \
-  V(_Uint16Array, []=, Uint16ArraySetIndexed, 1594961463)                      \
-  V(_Int16Array, [], Int16ArrayGetIndexed, 1699340532)                         \
-  V(_Int16Array, []=, Int16ArraySetIndexed, 799870496)                         \
-  V(_Int32Array, [], Int32ArrayGetIndexed, 2052925823)                         \
-  V(_Int32Array, []=, Int32ArraySetIndexed, 504626978)                         \
-  V(_Int64Array, [], Int64ArrayGetIndexed, 297668331)                          \
-  V(_Int64Array, []=, Int64ArraySetIndexed, 36465128)                          \
-  V(_Uint8ArrayView, [], Uint8ArrayViewGetIndexed, 662241408)                  \
-  V(_Uint8ArrayView, []=, Uint8ArrayViewSetIndexed, 1550171024)                \
-  V(_Int8ArrayView, [], Int8ArrayViewGetIndexed, 875752635)                    \
-  V(_Int8ArrayView, []=, Int8ArrayViewSetIndexed, 689961281)                   \
-  V(_ByteDataView, setInt8, ByteDataViewSetInt8, 1039277590)                   \
-  V(_ByteDataView, setUint8, ByteDataViewSetUint8, 497316431)                  \
-  V(_ByteDataView, setInt16, ByteDataViewSetInt16, 27520778)                   \
-  V(_ByteDataView, setUint16, ByteDataViewSetUint16, 1543151983)               \
-  V(_ByteDataView, setInt32, ByteDataViewSetInt32, 535913934)                  \
-  V(_ByteDataView, setUint32, ByteDataViewSetUint32, 596009393)                \
-  V(_ByteDataView, setInt64, ByteDataViewSetInt64, 787812783)                  \
-  V(_ByteDataView, setUint64, ByteDataViewSetUint64, 1078002910)               \
-  V(_ByteDataView, setFloat32, ByteDataViewSetFloat32, 2098528020)             \
-  V(_ByteDataView, setFloat64, ByteDataViewSetFloat64, 659619201)              \
-  V(_ByteDataView, getInt8, ByteDataViewGetInt8, 2117136369)                   \
-  V(_ByteDataView, getUint8, ByteDataViewGetUint8, 298860761)                  \
-  V(_ByteDataView, getInt16, ByteDataViewGetInt16, 975961124)                  \
-  V(_ByteDataView, getUint16, ByteDataViewGetUint16, 1503060990)               \
-  V(_ByteDataView, getInt32, ByteDataViewGetInt32, 1096620023)                 \
-  V(_ByteDataView, getUint32, ByteDataViewGetUint32, 1698446167)               \
-  V(_ByteDataView, getInt64, ByteDataViewGetInt64, 1950535797)                 \
-  V(_ByteDataView, getUint64, ByteDataViewGetUint64, 786884343)                \
-  V(_ByteDataView, getFloat32, ByteDataViewGetFloat32, 889064264)              \
-  V(_ByteDataView, getFloat64, ByteDataViewGetFloat64, 1577605354)             \
-  V(::, asin, MathASin, 1651042633)                                            \
-  V(::, acos, MathACos, 1139647090)                                            \
-  V(::, atan, MathATan, 1668754384)                                            \
-  V(::, atan2, MathATan2, 1931713076)                                          \
-  V(::, cos, MathCos, 1951197905)                                              \
-  V(::, exp, MathExp, 1809210829)                                              \
-  V(::, log, MathLog, 1620336448)                                              \
-  V(::, max, MathMax, 212291192)                                               \
-  V(::, min, MathMin, 478627534)                                               \
-  V(::, pow, MathPow, 582475257)                                               \
-  V(::, sin, MathSin, 1741396147)                                              \
-  V(::, sqrt, MathSqrt, 101545548)                                             \
-  V(::, tan, MathTan, 982072809)                                               \
-  V(Lists, copy, ListsCopy, 618211805)                                         \
-  V(_Bigint, get:_neg, Bigint_getNeg, 1151633263)                              \
-  V(_Bigint, get:_used, Bigint_getUsed, 1308648707)                            \
-  V(_Bigint, get:_digits, Bigint_getDigits, 1408181836)                        \
-  V(_HashVMBase, get:_index, LinkedHashMap_getIndex, 1431607529)               \
-  V(_HashVMBase, set:_index, LinkedHashMap_setIndex, 2007926178)               \
-  V(_HashVMBase, get:_data, LinkedHashMap_getData, 958070909)                  \
-  V(_HashVMBase, set:_data, LinkedHashMap_setData, 1134236592)                 \
-  V(_HashVMBase, get:_usedData, LinkedHashMap_getUsedData, 421669312)          \
-  V(_HashVMBase, set:_usedData, LinkedHashMap_setUsedData, 1152062737)         \
-  V(_HashVMBase, get:_hashMask, LinkedHashMap_getHashMask, 969476186)          \
-  V(_HashVMBase, set:_hashMask, LinkedHashMap_setHashMask, 1781420082)         \
-  V(_HashVMBase, get:_deletedKeys, LinkedHashMap_getDeletedKeys, 63633039)     \
-  V(_HashVMBase, set:_deletedKeys, LinkedHashMap_setDeletedKeys, 2079107858)   \
-  V(Uint8List, ., Uint8ListFactory, 1844890525)                                \
-  V(Int8List, ., Int8ListFactory, 1802068996)                                  \
-  V(Uint16List, ., Uint16ListFactory, 1923962567)                              \
-  V(Int16List, ., Int16ListFactory, 2000007495)                                \
-  V(Uint32List, ., Uint32ListFactory, 1836019363)                              \
-  V(Int32List, ., Int32ListFactory, 442847136)                                 \
-  V(Uint64List, ., Uint64ListFactory, 196248223)                               \
-  V(Int64List, ., Int64ListFactory, 1668869084)                                \
-  V(Float32List, ., Float32ListFactory, 1367032554)                            \
-  V(Float64List, ., Float64ListFactory, 1886443347)                            \
-  V(Int32x4List, ., Int32x4ListFactory, 1409401969)                            \
-  V(Float32x4List, ., Float32x4ListFactory, 556438009)                         \
-  V(Float64x2List, ., Float64x2ListFactory, 1269752759)
+  V(Object, ==, ObjectEquals, 291909336)                                       \
+  V(_List, get:length, ObjectArrayLength, 630471378)                           \
+  V(_ImmutableList, get:length, ImmutableArrayLength, 630471378)               \
+  V(_TypedList, get:length, TypedDataLength, 546364442)                        \
+  V(_GrowableList, get:length, GrowableArrayLength, 417111542)                 \
+  V(_GrowableList, add, GrowableListAdd, 242296201)                            \
+  V(_GrowableList, removeLast, GrowableListRemoveLast, 1655383014)             \
+  V(_StringBase, get:length, StringBaseLength, 707533587)                      \
+  V(ListIterator, moveNext, ListIteratorMoveNext, 1467737539)                  \
+  V(_FixedSizeArrayIterator, moveNext, FixedListIteratorMoveNext, 784200630)   \
+  V(_GrowableList, get:iterator, GrowableArrayIterator, 1840323187)            \
+  V(_GrowableList, forEach, GrowableArrayForEach, 620771070)                   \
+  V(_List, ., ObjectArrayAllocate, 184405219)                                  \
+  V(_List, [], ObjectArrayGetIndexed, 360400496)                               \
+  V(_List, []=, ObjectArraySetIndexed, 886228780)                              \
+  V(ListMixin, get:isEmpty, ListMixinIsEmpty, 2021497798)                      \
+  V(_List, get:iterator, ObjectArrayIterator, 1930956161)                      \
+  V(_List, forEach, ObjectArrayForEach, 180150673)                             \
+  V(_List, _slice, ObjectArraySlice, 1785552519)                               \
+  V(_ImmutableList, get:iterator, ImmutableArrayIterator, 1930956161)          \
+  V(_ImmutableList, forEach, ImmutableArrayForEach, 180150673)                 \
+  V(_ImmutableList, [], ImmutableArrayGetIndexed, 360400496)                   \
+  V(_GrowableList, [], GrowableArrayGetIndexed, 1957529650)                    \
+  V(_GrowableList, []=, GrowableArraySetIndexed, 225246870)                    \
+  V(_Float32Array, [], Float32ArrayGetIndexed, 1002307136)                     \
+  V(_Float32Array, []=, Float32ArraySetIndexed, 279546769)                     \
+  V(_Float64Array, [], Float64ArrayGetIndexed, 816943529)                      \
+  V(_Float64Array, []=, Float64ArraySetIndexed, 1929239576)                    \
+  V(_Int8Array, [], Int8ArrayGetIndexed, 1141846285)                           \
+  V(_Int8Array, []=, Int8ArraySetIndexed, 1486839324)                          \
+  V(_Uint8Array, [], Uint8ArrayGetIndexed, 513704632)                          \
+  V(_Uint8Array, []=, Uint8ArraySetIndexed, 2123520783)                        \
+  V(_Uint8ClampedArray, [], Uint8ClampedArrayGetIndexed, 513704632)            \
+  V(_Uint8ClampedArray, []=, Uint8ClampedArraySetIndexed, 1015846567)          \
+  V(_Uint16Array, [], Uint16ArrayGetIndexed, 118958722)                        \
+  V(_Uint16Array, []=, Uint16ArraySetIndexed, 658824450)                       \
+  V(_Int16Array, [], Int16ArrayGetIndexed, 1826359619)                         \
+  V(_Int16Array, []=, Int16ArraySetIndexed, 1108689116)                        \
+  V(_Int32Array, [], Int32ArrayGetIndexed, 681203163)                          \
+  V(_Int32Array, []=, Int32ArraySetIndexed, 1786886245)                        \
+  V(_Int64Array, [], Int64ArrayGetIndexed, 1883155004)                         \
+  V(_Int64Array, []=, Int64ArraySetIndexed, 905815059)                         \
+  V(_Uint8ArrayView, [], Uint8ArrayViewGetIndexed, 215420949)                  \
+  V(_Uint8ArrayView, []=, Uint8ArrayViewSetIndexed, 1138146450)                \
+  V(_Int8ArrayView, [], Int8ArrayViewGetIndexed, 1003520035)                   \
+  V(_Int8ArrayView, []=, Int8ArrayViewSetIndexed, 225448326)                   \
+  V(_ByteDataView, setInt8, ByteDataViewSetInt8, 1091734252)                   \
+  V(_ByteDataView, setUint8, ByteDataViewSetUint8, 549773093)                  \
+  V(_ByteDataView, setInt16, ByteDataViewSetInt16, 1580120352)                 \
+  V(_ByteDataView, setUint16, ByteDataViewSetUint16, 948267909)                \
+  V(_ByteDataView, setInt32, ByteDataViewSetInt32, 2088513508)                 \
+  V(_ByteDataView, setUint32, ByteDataViewSetUint32, 1125319)                  \
+  V(_ByteDataView, setInt64, ByteDataViewSetInt64, 192928709)                  \
+  V(_ByteDataView, setUint64, ByteDataViewSetUint64, 483118836)                \
+  V(_ByteDataView, setFloat32, ByteDataViewSetFloat32, 1241910514)             \
+  V(_ByteDataView, setFloat64, ByteDataViewSetFloat64, 1950485343)             \
+  V(_ByteDataView, getInt8, ByteDataViewGetInt8, 1939363561)                   \
+  V(_ByteDataView, getUint8, ByteDataViewGetUint8, 121087953)                  \
+  V(_ByteDataView, getInt16, ByteDataViewGetInt16, 591911343)                  \
+  V(_ByteDataView, getUint16, ByteDataViewGetUint16, 2114157459)               \
+  V(_ByteDataView, getInt32, ByteDataViewGetInt32, 712570242)                  \
+  V(_ByteDataView, getUint32, ByteDataViewGetUint32, 162058988)                \
+  V(_ByteDataView, getInt64, ByteDataViewGetInt64, 1566486016)                 \
+  V(_ByteDataView, getUint64, ByteDataViewGetUint64, 1397980812)               \
+  V(_ByteDataView, getFloat32, ByteDataViewGetFloat32, 1251636679)             \
+  V(_ByteDataView, getFloat64, ByteDataViewGetFloat64, 1940177769)             \
+  V(::, asin, MathASin, 848695059)                                             \
+  V(::, acos, MathACos, 337299516)                                             \
+  V(::, atan, MathATan, 866406810)                                             \
+  V(::, atan2, MathATan2, 1901969510)                                          \
+  V(::, cos, MathCos, 1148850331)                                              \
+  V(::, exp, MathExp, 1006863255)                                              \
+  V(::, log, MathLog, 817988874)                                               \
+  V(::, max, MathMax, 1410473322)                                              \
+  V(::, min, MathMin, 1115051548)                                              \
+  V(::, pow, MathPow, 864430827)                                               \
+  V(::, sin, MathSin, 939048573)                                               \
+  V(::, sqrt, MathSqrt, 1446681622)                                            \
+  V(::, tan, MathTan, 179725235)                                               \
+  V(Lists, copy, ListsCopy, 564237562)                                         \
+  V(_Bigint, get:_neg, Bigint_getNeg, 1681019799)                              \
+  V(_Bigint, get:_used, Bigint_getUsed, 1439136438)                            \
+  V(_Bigint, get:_digits, Bigint_getDigits, 769722770)                         \
+  V(_HashVMBase, get:_index, LinkedHashMap_getIndex, 2048715833)               \
+  V(_HashVMBase, set:_index, LinkedHashMap_setIndex, 1882796480)               \
+  V(_HashVMBase, get:_data, LinkedHashMap_getData, 942992497)                  \
+  V(_HashVMBase, set:_data, LinkedHashMap_setData, 1410623019)                 \
+  V(_HashVMBase, get:_usedData, LinkedHashMap_getUsedData, 1698421819)         \
+  V(_HashVMBase, set:_usedData, LinkedHashMap_setUsedData, 1858754514)         \
+  V(_HashVMBase, get:_hashMask, LinkedHashMap_getHashMask, 98745045)           \
+  V(_HashVMBase, set:_hashMask, LinkedHashMap_setHashMask, 340628211)          \
+  V(_HashVMBase, get:_deletedKeys, LinkedHashMap_getDeletedKeys, 1340385546)   \
+  V(_HashVMBase, set:_deletedKeys, LinkedHashMap_setDeletedKeys, 638315987)    \
+  V(Uint8List, ., Uint8ListFactory, 1885328419)                                \
+  V(Int8List, ., Int8ListFactory, 551286096)                                   \
+  V(Uint16List, ., Uint16ListFactory, 2018994846)                              \
+  V(Int16List, ., Int16ListFactory, 1934285336)                                \
+  V(Uint32List, ., Uint32ListFactory, 990865607)                               \
+  V(Int32List, ., Int32ListFactory, 2017670015)                                \
+  V(Uint64List, ., Uint64ListFactory, 1593070032)                              \
+  V(Int64List, ., Int64ListFactory, 1071205588)                                \
+  V(Float32List, ., Float32ListFactory, 1015272745)                            \
+  V(Float64List, ., Float64ListFactory, 626315429)                             \
+  V(Int32x4List, ., Int32x4ListFactory, 1693091079)                            \
+  V(Float32x4List, ., Float32x4ListFactory, 585154381)                         \
+  V(Float64x2List, ., Float64x2ListFactory, 874435184)
 
 
 // A list of core function that should never be inlined.
 #define INLINE_BLACK_LIST(V)                                                   \
-  V(_Bigint, _lsh, Bigint_lsh, 1457834861)                                     \
-  V(_Bigint, _rsh, Bigint_rsh, 1619318930)                                     \
-  V(_Bigint, _absAdd, Bigint_absAdd, 1029882563)                               \
-  V(_Bigint, _absSub, Bigint_absSub, 1407667556)                               \
-  V(_Bigint, _mulAdd, Bigint_mulAdd, 1408994809)                               \
-  V(_Bigint, _sqrAdd, Bigint_sqrAdd, 2025116181)                               \
-  V(_Bigint, _estQuotientDigit, Bigint_estQuotientDigit, 919247767)            \
-  V(_Montgomery, _mulMod, Montgomery_mulMod, 401580778)                        \
+  V(_Bigint, _lsh, Bigint_lsh, 834311957)                                      \
+  V(_Bigint, _rsh, Bigint_rsh, 333337658)                                      \
+  V(_Bigint, _absAdd, Bigint_absAdd, 473436659)                                \
+  V(_Bigint, _absSub, Bigint_absSub, 1018678324)                               \
+  V(_Bigint, _mulAdd, Bigint_mulAdd, 571005736)                                \
+  V(_Bigint, _sqrAdd, Bigint_sqrAdd, 372896038)                                \
+  V(_Bigint, _estQuotientDigit, Bigint_estQuotientDigit, 540033329)            \
+  V(_Montgomery, _mulMod, Montgomery_mulMod, 118781828)                        \
 
 // A list of core functions that internally dispatch based on received id.
 #define POLYMORPHIC_TARGET_LIST(V)                                             \
-  V(_StringBase, [], StringBaseCharAt, 408544820)                              \
-  V(_StringBase, codeUnitAt, StringBaseCodeUnitAt, 397735324)                  \
-  V(_TypedList, _getInt8, ByteArrayBaseGetInt8, 1541411498)                    \
-  V(_TypedList, _getUint8, ByteArrayBaseGetUint8, 1032404349)                  \
-  V(_TypedList, _getInt16, ByteArrayBaseGetInt16, 381073990)                   \
-  V(_TypedList, _getUint16, ByteArrayBaseGetUint16, 1142676276)                \
-  V(_TypedList, _getInt32, ByteArrayBaseGetInt32, 330269934)                   \
-  V(_TypedList, _getUint32, ByteArrayBaseGetUint32, 59490554)                  \
-  V(_TypedList, _getFloat32, ByteArrayBaseGetFloat32, 393003933)               \
-  V(_TypedList, _getFloat64, ByteArrayBaseGetFloat64, 1792407200)              \
-  V(_TypedList, _getFloat32x4, ByteArrayBaseGetFloat32x4, 1338379857)          \
-  V(_TypedList, _getInt32x4, ByteArrayBaseGetInt32x4, 1469917805)              \
-  V(_TypedList, _setInt8, ByteArrayBaseSetInt8, 1892735922)                    \
-  V(_TypedList, _setUint8, ByteArrayBaseSetInt8, 1608794041)                   \
-  V(_TypedList, _setInt16, ByteArrayBaseSetInt16, 117380972)                   \
-  V(_TypedList, _setUint16, ByteArrayBaseSetInt16, 200484754)                  \
-  V(_TypedList, _setInt32, ByteArrayBaseSetInt32, 1020151991)                  \
-  V(_TypedList, _setUint32, ByteArrayBaseSetUint32, 1175056602)                \
-  V(_TypedList, _setFloat32, ByteArrayBaseSetFloat32, 460607665)               \
-  V(_TypedList, _setFloat64, ByteArrayBaseSetFloat64, 284787790)               \
-  V(_TypedList, _setFloat32x4, ByteArrayBaseSetFloat32x4, 262426120)           \
-  V(_TypedList, _setInt32x4, ByteArrayBaseSetInt32x4, 613041888)               \
+  V(_StringBase, [], StringBaseCharAt, 754527301)                              \
+  V(_StringBase, codeUnitAt, StringBaseCodeUnitAt, 1436590579)                 \
+  V(_TypedList, _getInt8, ByteArrayBaseGetInt8, 187609847)                     \
+  V(_TypedList, _getUint8, ByteArrayBaseGetUint8, 1826086346)                  \
+  V(_TypedList, _getInt16, ByteArrayBaseGetInt16, 1174755987)                  \
+  V(_TypedList, _getUint16, ByteArrayBaseGetUint16, 1936358273)                \
+  V(_TypedList, _getInt32, ByteArrayBaseGetInt32, 1123951931)                  \
+  V(_TypedList, _getUint32, ByteArrayBaseGetUint32, 853172551)                 \
+  V(_TypedList, _getFloat32, ByteArrayBaseGetFloat32, 165422183)               \
+  V(_TypedList, _getFloat64, ByteArrayBaseGetFloat64, 1564825450)              \
+  V(_TypedList, _getFloat32x4, ByteArrayBaseGetFloat32x4, 1123952315)          \
+  V(_TypedList, _getInt32x4, ByteArrayBaseGetInt32x4, 831892409)               \
+  V(_TypedList, _setInt8, ByteArrayBaseSetInt8, 2043203289)                    \
+  V(_TypedList, _setUint8, ByteArrayBaseSetInt8, 1759261408)                   \
+  V(_TypedList, _setInt16, ByteArrayBaseSetInt16, 267848339)                   \
+  V(_TypedList, _setUint16, ByteArrayBaseSetInt16, 350952121)                  \
+  V(_TypedList, _setInt32, ByteArrayBaseSetInt32, 1170619358)                  \
+  V(_TypedList, _setUint32, ByteArrayBaseSetUint32, 1325523969)                \
+  V(_TypedList, _setFloat32, ByteArrayBaseSetFloat32, 541136999)               \
+  V(_TypedList, _setFloat64, ByteArrayBaseSetFloat64, 365317124)               \
+  V(_TypedList, _setFloat32x4, ByteArrayBaseSetFloat32x4, 1766802707)          \
+  V(_TypedList, _setInt32x4, ByteArrayBaseSetInt32x4, 2075229300)              \
 
 // Forward declarations.
 class Function;
@@ -518,21 +515,21 @@
 // List of recognized list factories:
 // (factory-name-symbol, result-cid, fingerprint).
 #define RECOGNIZED_LIST_FACTORY_LIST(V)                                        \
-  V(_ListFactory, kArrayCid, 850375012)                                        \
-  V(_GrowableListWithData, kGrowableObjectArrayCid, 2094352700)                \
-  V(_GrowableListFactory, kGrowableObjectArrayCid, 1518848600)                 \
-  V(_Int8ArrayFactory, kTypedDataInt8ArrayCid, 439914696)                      \
-  V(_Uint8ArrayFactory, kTypedDataUint8ArrayCid, 1442599030)                   \
-  V(_Uint8ClampedArrayFactory, kTypedDataUint8ClampedArrayCid, 1320015159)     \
-  V(_Int16ArrayFactory, kTypedDataInt16ArrayCid, 2132591678)                   \
-  V(_Uint16ArrayFactory, kTypedDataUint16ArrayCid, 1704816032)                 \
-  V(_Int32ArrayFactory, kTypedDataInt32ArrayCid, 1115045147)                   \
-  V(_Uint32ArrayFactory, kTypedDataUint32ArrayCid, 1385852190)                 \
-  V(_Int64ArrayFactory, kTypedDataInt64ArrayCid, 1193438555)                   \
-  V(_Uint64ArrayFactory, kTypedDataUint64ArrayCid, 410766246)                  \
-  V(_Float64ArrayFactory, kTypedDataFloat64ArrayCid, 1430631000)               \
-  V(_Float32ArrayFactory, kTypedDataFloat32ArrayCid, 1194249144)               \
-  V(_Float32x4ArrayFactory, kTypedDataFloat32x4ArrayCid, 158753569)            \
+  V(_ListFactory, kArrayCid, 184405219)                                        \
+  V(_GrowableListWithData, kGrowableObjectArrayCid, 131424500)                 \
+  V(_GrowableListFactory, kGrowableObjectArrayCid, 664918385)                  \
+  V(_Int8ArrayFactory, kTypedDataInt8ArrayCid, 484088513)                      \
+  V(_Uint8ArrayFactory, kTypedDataUint8ArrayCid, 1830561671)                   \
+  V(_Uint8ClampedArrayFactory, kTypedDataUint8ClampedArrayCid, 980532456)      \
+  V(_Int16ArrayFactory, kTypedDataInt16ArrayCid, 2095566414)                   \
+  V(_Uint16ArrayFactory, kTypedDataUint16ArrayCid, 248627537)                  \
+  V(_Int32ArrayFactory, kTypedDataInt32ArrayCid, 836050202)                    \
+  V(_Uint32ArrayFactory, kTypedDataUint32ArrayCid, 102123815)                  \
+  V(_Int64ArrayFactory, kTypedDataInt64ArrayCid, 1820730838)                   \
+  V(_Uint64ArrayFactory, kTypedDataUint64ArrayCid, 1668399825)                 \
+  V(_Float64ArrayFactory, kTypedDataFloat64ArrayCid, 1700923139)               \
+  V(_Float32ArrayFactory, kTypedDataFloat32ArrayCid, 307228626)                \
+  V(_Float32x4ArrayFactory, kTypedDataFloat32x4ArrayCid, 1083909924)           \
 
 
 // Class that recognizes factories and returns corresponding result cid.
diff --git a/runtime/vm/native_arguments.h b/runtime/vm/native_arguments.h
index 1763c8c..af27a37 100644
--- a/runtime/vm/native_arguments.h
+++ b/runtime/vm/native_arguments.h
@@ -14,7 +14,6 @@
 
 namespace dart {
 
-DECLARE_FLAG(bool, deoptimize_alot);
 DECLARE_FLAG(bool, trace_natives);
 DECLARE_FLAG(bool, verify_on_transition);
 
diff --git a/runtime/vm/native_entry.cc b/runtime/vm/native_entry.cc
index a28a779..a5c79d3 100644
--- a/runtime/vm/native_entry.cc
+++ b/runtime/vm/native_entry.cc
@@ -120,6 +120,12 @@
 void NativeEntry::NativeCallWrapper(Dart_NativeArguments args,
                                     Dart_NativeFunction func) {
   CHECK_STACK_ALIGNMENT;
+  NativeCallWrapperNoStackCheck(args, func);
+}
+
+
+void NativeEntry::NativeCallWrapperNoStackCheck(Dart_NativeArguments args,
+                                                Dart_NativeFunction func) {
   VERIFY_ON_TRANSITION;
   NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
   /* Tell MemorySanitizer 'arguments' is initialized by generated code. */
@@ -281,7 +287,9 @@
 
   // Tail-call resolved target.
   if (call_through_wrapper) {
-    NativeEntry::NativeCallWrapper(
+    // Because this call is within a compilation unit, Clang doesn't respect
+    // the ABI alignment here.
+    NativeEntry::NativeCallWrapperNoStackCheck(
         args, reinterpret_cast<Dart_NativeFunction>(target_function));
   } else {
     target_function(arguments);
diff --git a/runtime/vm/native_entry.h b/runtime/vm/native_entry.h
index 2e90ffc..9557073 100644
--- a/runtime/vm/native_entry.h
+++ b/runtime/vm/native_entry.h
@@ -120,7 +120,11 @@
 
   static uword LinkNativeCallEntry();
   static void LinkNativeCall(Dart_NativeArguments args);
+
  private:
+  static void NativeCallWrapperNoStackCheck(Dart_NativeArguments args,
+                                            Dart_NativeFunction func);
+
   static bool ReturnValueIsError(NativeArguments* arguments);
   static void PropagateErrors(NativeArguments* arguments);
 };
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index aea7d1f..300070b 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -55,14 +55,11 @@
 DEFINE_FLAG(bool, show_internal_names, false,
     "Show names of internal classes (e.g. \"OneByteString\") in error messages "
     "instead of showing the corresponding interface names (e.g. \"String\")");
-DEFINE_FLAG(bool, use_field_guards, true, "Guard field cids.");
 DEFINE_FLAG(bool, use_lib_cache, true, "Use library name cache");
 DEFINE_FLAG(bool, ignore_patch_signature_mismatch, false,
             "Ignore patch file member signature mismatch.");
 
 DECLARE_FLAG(charp, coverage_dir);
-DECLARE_FLAG(bool, load_deferred_eagerly);
-DECLARE_FLAG(bool, precompilation);
 DECLARE_FLAG(bool, show_invisible_frames);
 DECLARE_FLAG(bool, trace_deoptimization);
 DECLARE_FLAG(bool, trace_deoptimization_verbose);
@@ -216,12 +213,15 @@
 //   _MyClass@6328321. -> _MyClass
 //   _MyClass@6328321.named -> _MyClass.named
 //
-RawString* String::IdentifierPrettyName(const String& name) {
+RawString* String::ScrubName(const String& name) {
   Zone* zone = Thread::Current()->zone();
+
+NOT_IN_PRODUCT(
   if (name.Equals(Symbols::TopLevel())) {
     // Name of invisible top-level class.
     return Symbols::Empty().raw();
   }
+)
 
   const char* cname = name.ToCString();
   ASSERT(strlen(cname) == static_cast<size_t>(name.Length()));
@@ -266,6 +266,7 @@
     unmangled_name = MergeSubStrings(zone, unmangled_segments, sum_segment_len);
   }
 
+NOT_IN_PRODUCT(
   intptr_t len = sum_segment_len;
   intptr_t start = 0;
   intptr_t dot_pos = -1;  // Position of '.' in the name, if any.
@@ -314,12 +315,14 @@
   }
 
   unmangled_name = MergeSubStrings(zone, unmangled_segments, final_len);
+)
 
   return Symbols::New(unmangled_name);
 }
 
 
-RawString* String::IdentifierPrettyNameRetainPrivate(const String& name) {
+RawString* String::ScrubNameRetainPrivate(const String& name) {
+NOT_IN_PRODUCT(
   intptr_t len = name.Length();
   intptr_t start = 0;
   intptr_t at_pos = -1;  // Position of '@' in the name, if any.
@@ -362,6 +365,8 @@
   }
 
   return result.raw();
+)
+  return name.raw();  // In PRODUCT, return argument unchanged.
 }
 
 
@@ -1097,11 +1102,11 @@
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
   ASSERT(isolate == thread->isolate());
-#ifndef PRODUCT
+NOT_IN_PRODUCT(
   TimelineDurationScope tds(thread,
                             isolate->GetIsolateStream(),
                             "Object::Init");
-#endif
+)
 
 #if defined(DART_NO_SNAPSHOT)
   // Object::Init version when we are running in a version of dart that does
@@ -1375,7 +1380,8 @@
   ASSERT(lib.raw() == Library::MirrorsLibrary());
 
   cls = Class::New<MirrorReference>();
-  RegisterPrivateClass(cls, Symbols::_MirrorReference(), lib));
+  RegisterPrivateClass(cls, Symbols::_MirrorReference(), lib);
+)
 
   // Pre-register the collection library so we can place the vm class
   // LinkedHashMap there rather than the core library.
@@ -1917,18 +1923,17 @@
 }
 
 
-RawString* Class::PrettyName() const {
-  return GeneratePrettyName();
+RawString* Class::ScrubbedName() const {
+  return String::ScrubName(String::Handle(Name()));
 }
 
 
 RawString* Class::UserVisibleName() const {
-#if defined(PRODUCT)
-  return raw_ptr()->name_;
-#else  // defined(PRODUCT)
+NOT_IN_PRODUCT(
   ASSERT(raw_ptr()->user_name_ != String::null());
   return raw_ptr()->user_name_;
-#endif  // defined(PRODUCT)
+)
+  return GenerateUserVisibleName();  // No caching in PRODUCT, regenerate.
 }
 
 
@@ -3012,7 +3017,8 @@
   intptr_t len = value.Length();
   for (intptr_t i = 0; i < len; i++) {
     field ^= value.At(i);
-    ASSERT(field.owner() == raw());
+    ASSERT(field.IsOriginal());
+    ASSERT(field.Owner() == raw());
   }
 #endif
   // The value of static fields is already initialized to null.
@@ -3161,6 +3167,7 @@
 
 
 void Class::set_name(const String& value) const {
+  ASSERT(raw_ptr()->name_ == String::null());
   ASSERT(value.IsSymbol());
   StorePointer(&raw_ptr()->name_, value.raw());
 NOT_IN_PRODUCT(
@@ -3182,16 +3189,11 @@
 )
 
 
-RawString* Class::GeneratePrettyName() const {
-  const String& name = String::Handle(Name());
-  return String::IdentifierPrettyName(name);
-}
-
-
 RawString* Class::GenerateUserVisibleName() const {
   if (FLAG_show_internal_names) {
     return Name();
   }
+NOT_IN_PRODUCT(
   switch (id()) {
     case kNullCid:
       return Symbols::Null().raw();
@@ -3323,11 +3325,10 @@
     case kTypedDataFloat64ArrayCid:
     case kExternalTypedDataFloat64ArrayCid:
       return Symbols::Float64List().raw();
-    default:
-      const String& name = String::Handle(Name());
-      return String::IdentifierPrettyName(name);
   }
-  UNREACHABLE();
+)
+  const String& name = String::Handle(Name());
+  return String::ScrubName(name);
 }
 
 
@@ -3557,6 +3558,8 @@
     ASSERT(!types.IsNull() && (types.Length() > 1));
     ASSERT((types.At(0) == Object::null()) || (types.At(0) == type.raw()));
     types.SetAt(0, type);
+    // Makes sure that 'canonical_types' has not changed.
+    ASSERT(types.raw() == canonical_types());
   }
 }
 
@@ -4126,6 +4129,84 @@
 }
 
 
+// Returns AbstractType::null() if type not found. Modifies index to the last
+// position looked up.
+RawAbstractType* Class::LookupCanonicalType(
+    Zone* zone, const AbstractType& lookup_type, intptr_t* index) const {
+  Array& canonical_types = Array::Handle(zone);
+  canonical_types ^= this->canonical_types();
+  if (canonical_types.IsNull()) {
+    return AbstractType::null();
+  }
+  AbstractType& type = Type::Handle(zone);
+  const intptr_t length = canonical_types.Length();
+  while (*index < length) {
+    type ^= canonical_types.At(*index);
+    if (type.IsNull()) {
+      break;
+    }
+    ASSERT(type.IsFinalized());
+    if (lookup_type.Equals(type)) {
+      ASSERT(type.IsCanonical());
+      return type.raw();
+    }
+    *index = *index + 1;
+  }
+  return AbstractType::null();
+}
+
+
+// Canonicalizing the type arguments may have changed the index, may have
+// grown the table, or may even have canonicalized this type. Therefore
+// conrtinue search for canonical type at the last index visited.
+RawAbstractType* Class::LookupOrAddCanonicalType(
+    const AbstractType& lookup_type, intptr_t start_index) const {
+  Thread* thread = Thread::Current();
+  Zone* zone = thread->zone();
+  Isolate* isolate = thread->isolate();
+  AbstractType& type = Type::Handle(zone);
+  intptr_t index = start_index;
+  type ^= LookupCanonicalType(zone, lookup_type, &index);
+
+  if (!type.IsNull()) {
+    return type.raw();
+  }
+  {
+    SafepointMutexLocker ml(isolate->type_canonicalization_mutex());
+    // Lookup again, in case the canonicalization array changed.
+    Array& canonical_types = Array::Handle(zone);
+    canonical_types ^= this->canonical_types();
+    if (canonical_types.IsNull()) {
+      canonical_types = empty_array().raw();
+    }
+    const intptr_t length = canonical_types.Length();
+    // Start looking after previously looked up last position ('length').
+    type ^= LookupCanonicalType(zone, lookup_type, &index);
+    if (!type.IsNull()) {
+      return type.raw();
+    }
+
+    // 'lookup_type' is not canonicalized yet.
+    lookup_type.SetCanonical();
+
+    // The type needs to be added to the list. Grow the list if it is full.
+    if (index >= length) {
+      ASSERT((index == length) || ((index == 1) && (length == 0)));
+      const intptr_t new_length = (length > 64) ?
+          (length + 64) :
+          ((length == 0) ? 2 : (length * 2));
+      const Array& new_canonical_types = Array::Handle(
+          zone, Array::Grow(canonical_types, new_length, Heap::kOld));
+      new_canonical_types.SetAt(index, lookup_type);
+      this->set_canonical_types(new_canonical_types);
+    } else {
+      canonical_types.SetAt(index, lookup_type);
+    }
+  }
+  return lookup_type.raw();
+}
+
+
 const char* Class::ToCString() const {
   const Library& lib = Library::Handle(library());
   const char* library_name = lib.IsNull() ? "" : lib.ToCString();
@@ -4920,6 +5001,22 @@
 }
 
 
+RawString* TypeArguments::EnumerateURIs() const {
+  if (IsNull()) {
+    return Symbols::Empty().raw();
+  }
+  Zone* zone = Thread::Current()->zone();
+  AbstractType& type = AbstractType::Handle(zone);
+  const intptr_t num_types = Length();
+  GrowableHandlePtrArray<const String> pieces(zone, num_types);
+  for (intptr_t i = 0; i < num_types; i++) {
+    type = TypeAt(i);
+    pieces.Add(String::Handle(zone, type.EnumerateURIs()));
+  }
+  return Symbols::FromConcatAll(pieces);
+}
+
+
 const char* TypeArguments::ToCString() const {
   if (IsNull()) {
     return "NULL TypeArguments";
@@ -5942,7 +6039,7 @@
 
 bool Function::HasCompatibleParametersWith(const Function& other,
                                            Error* bound_error) const {
-  ASSERT(Isolate::Current()->flags().error_on_bad_override());
+  ASSERT(Isolate::Current()->error_on_bad_override());
   ASSERT((bound_error != NULL) && bound_error->IsNull());
   // Check that this function's signature type is a subtype of the other
   // function's signature type.
@@ -6655,68 +6752,36 @@
 }
 
 
-RawString* Function::PrettyName() const {
-  const String& str = String::Handle(name());
-  return String::IdentifierPrettyName(str);
-}
-
-
-const char* Function::QualifiedUserVisibleNameCString() const {
-  const String& str = String::Handle(QualifiedUserVisibleName());
-  return str.ToCString();
-}
-
-
 RawString* Function::UserVisibleName() const {
-  return PrettyName();
+  if (FLAG_show_internal_names) {
+    return name();
+  }
+  return String::ScrubName(String::Handle(name()));
 }
 
 
-RawString* Function::QualifiedPrettyName() const {
-  String& tmp = String::Handle();
-  const Class& cls = Class::Handle(Owner());
-
+RawString* Function::QualifiedName(NameVisibility name_visibility) const {
+  ASSERT(name_visibility != kInternalName);  // We never request it.
+  // A function's scrubbed name and its user visible name are identical.
+  String& result = String::Handle(UserVisibleName());
   if (IsClosureFunction()) {
-    if (IsLocalFunction() && !IsImplicitClosureFunction()) {
-      const Function& parent = Function::Handle(parent_function());
-      tmp = parent.QualifiedPrettyName();
-    } else {
-      return PrettyName();
-    }
-  } else {
-    if (cls.IsTopLevel()) {
-      return PrettyName();
-    } else {
-      tmp = cls.PrettyName();
+    Function& fun = Function::Handle(raw());
+    while (fun.IsLocalFunction() && !fun.IsImplicitClosureFunction()) {
+      fun = fun.parent_function();
+      result = String::Concat(Symbols::Dot(), result, Heap::kOld);
+      result = String::Concat(
+          String::Handle(fun.UserVisibleName()), result, Heap::kOld);
     }
   }
-  tmp = String::Concat(tmp, Symbols::Dot(), Heap::kOld);
-  const String& suffix = String::Handle(PrettyName());
-  return String::Concat(tmp, suffix, Heap::kOld);
-}
-
-
-RawString* Function::QualifiedUserVisibleName() const {
-  String& tmp = String::Handle();
   const Class& cls = Class::Handle(Owner());
-
-  if (IsClosureFunction()) {
-    if (IsLocalFunction() && !IsImplicitClosureFunction()) {
-      const Function& parent = Function::Handle(parent_function());
-      tmp = parent.QualifiedUserVisibleName();
-    } else {
-      return UserVisibleName();
-    }
-  } else {
-    if (cls.IsTopLevel()) {
-      return UserVisibleName();
-    } else {
-      tmp = cls.UserVisibleName();
-    }
+  if (!cls.IsTopLevel()) {
+    result = String::Concat(Symbols::Dot(), result, Heap::kOld);
+    const String& cls_name = String::Handle(
+        name_visibility == kScrubbedName ? cls.ScrubbedName()
+                                         : cls.UserVisibleName());
+    result = String::Concat(cls_name, result, Heap::kOld);
   }
-  tmp = String::Concat(tmp, Symbols::Dot());
-  const String& suffix = String::Handle(UserVisibleName());
-  return String::Concat(tmp, suffix);
+  return result.raw();
 }
 
 
@@ -6766,9 +6831,7 @@
 // Construct fingerprint from token stream. The token stream contains also
 // arguments.
 int32_t Function::SourceFingerprint() const {
-  uint32_t result = IsImplicitClosureFunction()
-      ? String::Handle(Function::Handle(parent_function()).Signature()).Hash()
-      : String::Handle(Signature()).Hash();
+  uint32_t result = 0;
   TokenStream::Iterator tokens_iterator(TokenStream::Handle(
       Script::Handle(script()).tokens()), token_pos());
   Object& obj = Object::Handle();
@@ -6818,6 +6881,9 @@
 void Function::RestoreICDataMap(
     ZoneGrowableArray<const ICData*>* deopt_id_to_ic_data,
     bool clone_ic_data) const {
+  if (FLAG_force_clone_compiler_objects) {
+    clone_ic_data = true;
+  }
   ASSERT(deopt_id_to_ic_data->is_empty());
   Zone* zone = Thread::Current()->zone();
   const Array& saved_ic_data = Array::Handle(zone, ic_data_array());
@@ -7014,6 +7080,31 @@
 }
 
 
+RawField* Field::CloneFromOriginal() const {
+  return this->Clone(*this);
+}
+
+
+RawField* Field::Original() const {
+  if (IsNull()) {
+    return Field::null();
+  }
+  Object& obj = Object::Handle(raw_ptr()->owner_);
+  if (obj.IsField()) {
+    return Field::RawCast(obj.raw());
+  } else {
+    return this->raw();
+  }
+}
+
+
+void Field::SetOriginal(const Field& value) const {
+  ASSERT(value.IsOriginal());
+  ASSERT(!value.IsNull());
+  StorePointer(&raw_ptr()->owner_, reinterpret_cast<RawObject*>(value.raw()));
+}
+
+
 RawString* Field::GetterName(const String& field_name) {
   return String::Concat(Symbols::GetterPrefix(), field_name);
 }
@@ -7068,12 +7159,27 @@
 
 void Field::set_name(const String& value) const {
   ASSERT(value.IsSymbol());
+  ASSERT(IsOriginal());
   StorePointer(&raw_ptr()->name_, value.raw());
 }
 
 
-RawClass* Field::owner() const {
-  const Object& obj = Object::Handle(raw_ptr()->owner_);
+RawObject* Field::RawOwner() const {
+  if (Original()) {
+    return raw_ptr()->owner_;
+  } else {
+    const Field& field = Field::Handle(Original());
+    ASSERT(field.IsOriginal());
+    ASSERT(!Object::Handle(field.raw_ptr()->owner_).IsField());
+    return field.raw_ptr()->owner_;
+  }
+}
+
+
+RawClass* Field::Owner() const {
+  const Field& field = Field::Handle(Original());
+  ASSERT(field.IsOriginal());
+  const Object& obj = Object::Handle(field.raw_ptr()->owner_);
   if (obj.IsClass()) {
     return Class::Cast(obj).raw();
   }
@@ -7082,8 +7188,10 @@
 }
 
 
-RawClass* Field::origin() const {
-  const Object& obj = Object::Handle(raw_ptr()->owner_);
+RawClass* Field::Origin() const {
+  const Field& field = Field::Handle(Original());
+  ASSERT(field.IsOriginal());
+  const Object& obj = Object::Handle(field.raw_ptr()->owner_);
   if (obj.IsClass()) {
     return Class::Cast(obj).raw();
   }
@@ -7092,8 +7200,10 @@
 }
 
 
-RawScript* Field::script() const {
-  const Object& obj = Object::Handle(raw_ptr()->owner_);
+RawScript* Field::Script() const {
+  const Field& field = Field::Handle(Original());
+  ASSERT(field.IsOriginal());
+  const Object& obj = Object::Handle(field.raw_ptr()->owner_);
   if (obj.IsClass()) {
     return Class::Cast(obj).script();
   }
@@ -7105,6 +7215,7 @@
 // Called at finalization time
 void Field::SetFieldType(const AbstractType& value) const {
   ASSERT(Thread::Current()->IsMutatorThread());
+  ASSERT(IsOriginal());
   ASSERT(!value.IsNull());
   if (value.raw() != type()) {
     StorePointer(&raw_ptr()->type_, value.raw());
@@ -7191,7 +7302,7 @@
 RawField* Field::Clone(const Class& new_owner) const {
   Field& clone = Field::Handle();
   clone ^= Object::Clone(*this, Heap::kOld);
-  const Class& owner = Class::Handle(this->owner());
+  const Class& owner = Class::Handle(this->Owner());
   const PatchClass& clone_owner =
       PatchClass::Handle(PatchClass::New(new_owner, owner));
   clone.set_owner(clone_owner);
@@ -7208,14 +7319,23 @@
 }
 
 
-RawString* Field::PrettyName() const {
-  const String& str = String::Handle(name());
-  return String::IdentifierPrettyName(str);
+RawField* Field::Clone(const Field& original) const {
+  if (original.IsNull()) {
+    return Field::null();
+  }
+  ASSERT(original.IsOriginal());
+  Field& clone = Field::Handle();
+  clone ^= Object::Clone(*this, Heap::kOld);
+  clone.SetOriginal(original);
+  return clone.raw();
 }
 
 
 RawString* Field::UserVisibleName() const {
-  return PrettyName();
+  if (FLAG_show_internal_names) {
+    return name();
+  }
+  return String::ScrubName(String::Handle(name()));
 }
 
 
@@ -7226,6 +7346,7 @@
 
 void Field::set_guarded_list_length(intptr_t list_length) const {
   ASSERT(Thread::Current()->IsMutatorThread());
+  ASSERT(IsOriginal());
   StoreSmi(&raw_ptr()->guarded_list_length_, Smi::New(list_length));
 }
 
@@ -7238,6 +7359,7 @@
 void Field::set_guarded_list_length_in_object_offset(
     intptr_t list_length_offset) const {
   ASSERT(Thread::Current()->IsMutatorThread());
+  ASSERT(IsOriginal());
   StoreNonPointer(&raw_ptr()->guarded_list_length_in_object_offset_,
                   static_cast<int8_t>(list_length_offset - kHeapObjectTag));
   ASSERT(guarded_list_length_in_object_offset() == list_length_offset);
@@ -7252,7 +7374,7 @@
   const char* kF1 = is_final() ? " final" : "";
   const char* kF2 = is_const() ? " const" : "";
   const char* field_name = String::Handle(name()).ToCString();
-  const Class& cls = Class::Handle(owner());
+  const Class& cls = Class::Handle(Owner());
   const char* cls_name = String::Handle(cls.Name()).ToCString();
   return OS::SCreate(Thread::Current()->zone(),
       "Field <%s.%s>:%s%s%s", cls_name, field_name, kF0, kF1, kF2);
@@ -7264,7 +7386,7 @@
 // named #f (or #f= in case of a setter).
 RawInstance* Field::AccessorClosure(bool make_setter) const {
   ASSERT(is_static());
-  const Class& field_owner = Class::Handle(owner());
+  const Class& field_owner = Class::Handle(Owner());
 
   String& closure_name = String::Handle(this->name());
   closure_name = Symbols::FromConcat(Symbols::HashMark(), closure_name);
@@ -7334,6 +7456,7 @@
 
 
 void Field::set_dependent_code(const Array& array) const {
+  ASSERT(IsOriginal());
   StorePointer(&raw_ptr()->dependent_code_, array.raw());
 }
 
@@ -7377,6 +7500,7 @@
 
 
 void Field::RegisterDependentCode(const Code& code) const {
+  ASSERT(IsOriginal());
   DEBUG_ASSERT(IsMutatorOrAtSafepoint());
   ASSERT(code.is_optimized());
   FieldDependentArray a(*this);
@@ -7385,6 +7509,7 @@
 
 
 void Field::DeoptimizeDependentCode() const {
+  ASSERT(IsOriginal());
   ASSERT(Thread::Current()->IsMutatorThread());
   FieldDependentArray a(*this);
   a.DisableCode();
@@ -7399,6 +7524,7 @@
 
 
 void Field::SetPrecompiledInitializer(const Function& initializer) const {
+  ASSERT(IsOriginal());
   StorePointer(&raw_ptr()->initializer_.precompiled_, initializer.raw());
 }
 
@@ -7410,12 +7536,14 @@
 
 
 void Field::SetSavedInitialStaticValue(const Instance& value) const {
+  ASSERT(IsOriginal());
   ASSERT(!HasPrecompiledInitializer());
   StorePointer(&raw_ptr()->initializer_.saved_value_, value.raw());
 }
 
 
 void Field::EvaluateInitializer() const {
+  ASSERT(IsOriginal());
   ASSERT(is_static());
   if (StaticValue() == Object::sentinel().raw()) {
     SetStaticValue(Object::transition_sentinel());
@@ -7517,6 +7645,7 @@
 
 
 void Field::InitializeGuardedListLengthInObjectOffset() const {
+  ASSERT(IsOriginal());
   if (needs_length_check() &&
       (guarded_list_length() != Field::kUnknownFixedLength)) {
     const intptr_t offset = GetListLengthOffset(guarded_cid());
@@ -7529,6 +7658,7 @@
 
 
 bool Field::UpdateGuardedCidAndLength(const Object& value) const {
+  ASSERT(IsOriginal());
   const intptr_t cid = value.GetClassId();
 
   if (guarded_cid() == kIllegalCid) {
@@ -7596,6 +7726,7 @@
 
 
 void Field::RecordStore(const Object& value) const {
+  ASSERT(IsOriginal());
   if (!FLAG_use_field_guards) {
     return;
   }
@@ -8957,7 +9088,7 @@
 
 static RawString* MakeFieldMetaName(const Field& field) {
   const String& cname =
-      String::Handle(MakeClassMetaName(Class::Handle(field.origin())));
+      String::Handle(MakeClassMetaName(Class::Handle(field.Origin())));
   GrowableHandlePtrArray<const String> pieces(Thread::Current()->zone(), 3);
   pieces.Add(cname);
   pieces.Add(Symbols::At());
@@ -8972,7 +9103,7 @@
   GrowableHandlePtrArray<const String> pieces(Thread::Current()->zone(), 3);
   pieces.Add(cname);
   pieces.Add(Symbols::At());
-  pieces.Add(String::Handle(func.QualifiedPrettyName()));
+  pieces.Add(String::Handle(func.QualifiedScrubbedName()));
   return Symbols::FromConcatAll(pieces);
 }
 
@@ -9422,7 +9553,7 @@
       } else if (entry.IsFunction()) {
         owner_script = Function::Cast(entry).script();
       } else if (entry.IsField()) {
-        owner_script = Field::Cast(entry).script();
+        owner_script = Field::Cast(entry).Script();
       } else {
         continue;
       }
@@ -10262,6 +10393,11 @@
   }
   ASSERT(is_deferred_load());
   ASSERT(num_imports() == 1);
+  if (Dart::IsRunningPrecompiledCode()) {
+    // The library list was tree-shaken away.
+    this->set_is_loaded();
+    return true;
+  }
   // This is a prefix for a deferred library. If the library is not loaded
   // yet and isn't being loaded, call the library tag handler to schedule
   // loading. Once all outstanding load requests have completed, the embedder
@@ -11019,6 +11155,87 @@
 }
 
 
+TokenPosition CodeSourceMap::TokenPositionForPCOffset(
+    uword pc_offset) const {
+  Iterator iterator(*this);
+
+  TokenPosition result = TokenPosition::kNoSource;
+
+  while (iterator.MoveNext()) {
+    if (iterator.PcOffset() > pc_offset) {
+      break;
+    }
+    result = iterator.TokenPos();
+  }
+
+  return result;
+}
+
+
+RawFunction* CodeSourceMap::FunctionForPCOffset(const Code& code,
+                                                const Function& function,
+                                                uword pc_offset) const {
+  GrowableArray<Function*> inlined_functions;
+  code.GetInlinedFunctionsAt(pc_offset, &inlined_functions);
+  if (inlined_functions.length() > 0) {
+    Function* inlined_function = inlined_functions[0];
+    return inlined_function->raw();
+  } else {
+    return function.raw();
+  }
+}
+
+
+RawScript* CodeSourceMap::ScriptForPCOffset(const Code& code,
+                                            const Function& function,
+                                            uword pc_offset) const {
+  const Function& func =
+      Function::Handle(FunctionForPCOffset(code, function, pc_offset));
+  return func.script();
+}
+
+
+void CodeSourceMap::Dump(const CodeSourceMap& code_source_map,
+                         const Code& code,
+                         const Function& function) {
+  const String& code_name = String::Handle(code.QualifiedName());
+  THR_Print("Dumping Code Source Map for %s\n", code_name.ToCString());
+  if (code_source_map.Length() == 0) {
+    THR_Print("<empty>\n");
+    return;
+  }
+
+  const int addr_width = kBitsPerWord / 4;
+
+  Iterator iterator(code_source_map);
+  Function& current_function = Function::Handle();
+  Script& current_script = Script::Handle();
+  TokenPosition tp;
+  while (iterator.MoveNext()) {
+    const uword pc_offset = iterator.PcOffset();
+    tp = code_source_map.TokenPositionForPCOffset(pc_offset);
+    current_function ^=
+        code_source_map.FunctionForPCOffset(code, function, pc_offset);
+    current_script ^=
+        code_source_map.ScriptForPCOffset(code, function, pc_offset);
+    if (current_function.IsNull() || current_script.IsNull()) {
+      THR_Print("%#-*" Px "\t%s\t%s\n", addr_width,
+                pc_offset,
+                tp.ToCString(),
+                code_name.ToCString());
+      continue;
+    }
+    const String& uri = String::Handle(current_script.url());
+    ASSERT(!uri.IsNull());
+    THR_Print("%#-*" Px "\t%s\t%s\t%s\n", addr_width,
+              pc_offset,
+              tp.ToCString(),
+              current_function.ToQualifiedCString(),
+              uri.ToCString());
+  }
+}
+
+
 intptr_t CodeSourceMap::Length() const {
   return raw_ptr()->length_;
 }
@@ -12775,6 +12992,29 @@
 }
 
 
+RawArray* Code::GetInlinedIdToTokenPos() const {
+  const Array& metadata = Array::Handle(raw_ptr()->inlined_metadata_);
+  if (metadata.IsNull()) {
+    return metadata.raw();
+  }
+  return reinterpret_cast<RawArray*>(
+      metadata.At(RawCode::kInlinedIdToTokenPosIndex));
+}
+
+
+void Code::SetInlinedIdToTokenPos(const Array& value) const {
+  if (raw_ptr()->inlined_metadata_ == Array::null()) {
+    StorePointer(&raw_ptr()->inlined_metadata_,
+                 Array::New(RawCode::kInlinedMetadataSize, Heap::kOld));
+  }
+  const Array& metadata = Array::Handle(raw_ptr()->inlined_metadata_);
+  ASSERT(!metadata.IsNull());
+  ASSERT(metadata.IsOld());
+  ASSERT(value.IsOld());
+  metadata.SetAt(RawCode::kInlinedIdToTokenPosIndex, value);
+}
+
+
 RawArray* Code::GetInlinedCallerIdMap() const {
   const Array& metadata = Array::Handle(raw_ptr()->inlined_metadata_);
   if (metadata.IsNull()) {
@@ -13032,7 +13272,6 @@
 }
 
 
-// Called by disassembler.
 RawString* Code::Name() const {
   const Object& obj = Object::Handle(owner());
   if (obj.IsNull()) {
@@ -13044,36 +13283,23 @@
   } else if (obj.IsClass()) {
     // Allocation stub.
     const Class& cls = Class::Cast(obj);
-    String& cls_name = String::Handle(cls.Name());
+    String& cls_name = String::Handle(cls.ScrubbedName());
     ASSERT(!cls_name.IsNull());
     return Symbols::FromConcat(Symbols::AllocationStubFor(), cls_name);
   } else {
     ASSERT(obj.IsFunction());
     // Dart function.
-    return Function::Cast(obj).name();
+    return Function::Cast(obj).UserVisibleName();  // Same as scrubbed name.
   }
 }
 
 
-RawString* Code::PrettyName() const {
+RawString* Code::QualifiedName() const {
   const Object& obj = Object::Handle(owner());
-  if (obj.IsNull()) {
-    // Regular stub.
-    const char* name = StubCode::NameOfStub(EntryPoint());
-    ASSERT(name != NULL);
-    const String& stub_name = String::Handle(String::New(name));
-    return String::Concat(Symbols::StubPrefix(), stub_name);
-  } else if (obj.IsClass()) {
-    // Allocation stub.
-    const Class& cls = Class::Cast(obj);
-    String& cls_name = String::Handle(cls.Name());
-    ASSERT(!cls_name.IsNull());
-    return String::Concat(Symbols::AllocationStubFor(), cls_name);
-  } else {
-    ASSERT(obj.IsFunction());
-    // Dart function.
-    return Function::Cast(obj).QualifiedPrettyName();
+  if (obj.IsFunction()) {
+    return Function::Cast(obj).QualifiedScrubbedName();
   }
+  return Name();
 }
 
 
@@ -13254,9 +13480,16 @@
       THR_Print("  %" Pd ": %s\n", i, function.ToQualifiedCString());
     }
   }
+  THR_Print("Inlined token pos:\n");
+  const Array& token_pos_map = Array::Handle(GetInlinedIdToTokenPos());
+  Smi& smi = Smi::Handle();
+  for (intptr_t i = 0; i < token_pos_map.Length(); i++) {
+    smi ^= token_pos_map.At(i);
+    TokenPosition tp = TokenPosition(smi.Value());
+    THR_Print("  %" Pd ": %s\n", i, tp.ToCString());
+  }
   THR_Print("Caller Inlining Ids:\n");
   const Array& caller_map = Array::Handle(GetInlinedCallerIdMap());
-  Smi& smi = Smi::Handle();
   for (intptr_t i = 0; i < caller_map.Length(); i++) {
     smi ^= caller_map.At(i);
     THR_Print("  iid: %" Pd " caller iid: %" Pd "\n", i, smi.Value());
@@ -14255,7 +14488,7 @@
           zone, other.InstantiateFrom(other_instantiator, bound_error,
                                       NULL, NULL, Heap::kOld));
       if ((bound_error != NULL) && !bound_error->IsNull()) {
-        ASSERT(Isolate::Current()->flags().type_checks());
+        ASSERT(Isolate::Current()->type_checks());
         return false;
       }
       if (instantiated_other.IsTypeRef()) {
@@ -14311,7 +14544,7 @@
     instantiated_other = other.InstantiateFrom(other_instantiator, bound_error,
                                                NULL, NULL, Heap::kOld);
     if ((bound_error != NULL) && !bound_error->IsNull()) {
-      ASSERT(Isolate::Current()->flags().type_checks());
+      ASSERT(Isolate::Current()->type_checks());
       return false;
     }
     if (instantiated_other.IsTypeRef()) {
@@ -14713,6 +14946,13 @@
 }
 
 
+RawString* AbstractType::EnumerateURIs() const {
+  // AbstractType is an abstract class.
+  UNREACHABLE();
+  return NULL;
+}
+
+
 RawAbstractType* AbstractType::OnlyBuddyInTrail(TrailPtr trail) const {
   if (trail == NULL) {
     return AbstractType::null();
@@ -14785,13 +15025,12 @@
 
 
 RawString* AbstractType::BuildName(NameVisibility name_visibility) const {
+  ASSERT(name_visibility != kScrubbedName);
   Zone* zone = Thread::Current()->zone();
   if (IsBoundedType()) {
     const AbstractType& type = AbstractType::Handle(
         BoundedType::Cast(*this).type());
-    if (name_visibility == kPrettyName) {
-      return type.BuildName(kPrettyName);
-    } else if (name_visibility == kUserVisibleName) {
+    if (name_visibility == kUserVisibleName) {
       return type.BuildName(kUserVisibleName);
     }
     GrowableHandlePtrArray<const String> pieces(zone, 5);
@@ -14861,8 +15100,6 @@
     }
     if (name_visibility == kInternalName) {
       class_name = cls.Name();
-    } else if (name_visibility == kPrettyName) {
-      class_name = cls.PrettyName();
     } else {
       ASSERT(name_visibility == kUserVisibleName);
       // Map internal types to their corresponding public interfaces.
@@ -14912,6 +15149,29 @@
 }
 
 
+// Same as user visible name, but including the URI of each occuring type.
+// Used to report errors involving types with identical names.
+//
+// e.g.
+//   MyClass<String>     -> MyClass<String> where
+//                            MyClass is from my_uri
+//                            String is from dart:core
+//   MyClass<dynamic, T> -> MyClass<dynamic, T> where
+//                            MyClass is from my_uri
+//                            T of OtherClass is from other_uri
+//   (MyClass) => int    -> (MyClass) => int where
+//                            MyClass is from my_uri
+//                            int is from dart:core
+RawString* AbstractType::UserVisibleNameWithURI() const {
+  Zone* zone = Thread::Current()->zone();
+  GrowableHandlePtrArray<const String> pieces(zone, 3);
+  pieces.Add(String::Handle(zone, BuildName(kUserVisibleName)));
+  pieces.Add(Symbols::SpaceWhereNewLine());
+  pieces.Add(String::Handle(zone, EnumerateURIs()));
+  return Symbols::FromConcatAll(pieces);
+}
+
+
 RawString* AbstractType::ClassName() const {
   if (HasResolvedTypeClass()) {
     return Class::Handle(type_class()).Name();
@@ -15007,14 +15267,14 @@
   // type and/or malbounded parameter types, which will then be encountered here
   // at run time.
   if (IsMalbounded()) {
-    ASSERT(Isolate::Current()->flags().type_checks());
+    ASSERT(Isolate::Current()->type_checks());
     if ((bound_error != NULL) && bound_error->IsNull()) {
       *bound_error = error();
     }
     return false;
   }
   if (other.IsMalbounded()) {
-    ASSERT(Isolate::Current()->flags().type_checks());
+    ASSERT(Isolate::Current()->type_checks());
     if ((bound_error != NULL) && bound_error->IsNull()) {
       *bound_error = other.error();
     }
@@ -15265,7 +15525,7 @@
 
 
 bool Type::IsMalbounded() const {
-  if (!Isolate::Current()->flags().type_checks()) {
+  if (!Isolate::Current()->type_checks()) {
     return false;
   }
   if (raw_ptr()->error_ == LanguageError::null()) {
@@ -15285,7 +15545,7 @@
     return true;
   }
   ASSERT(type_error.kind() == Report::kMalboundedType);
-  return Isolate::Current()->flags().type_checks();
+  return Isolate::Current()->type_checks();
 }
 
 
@@ -15569,9 +15829,14 @@
       set_arguments(type_args);
       type = cls.CanonicalType();  // May be set while canonicalizing type args.
       if (type.IsNull()) {
-        cls.set_canonical_types(*this);
-        SetCanonical();
-        return this->raw();
+        MutexLocker ml(isolate->type_canonicalization_mutex());
+        // Recheck if type exists.
+        type = cls.CanonicalType();
+        if (type.IsNull()) {
+          SetCanonical();
+          cls.set_canonical_types(*this);
+          return this->raw();
+        }
       }
     }
     ASSERT(this->Equals(type));
@@ -15616,43 +15881,28 @@
     return this->raw();
   }
   set_arguments(type_args);
-
-  // Canonicalizing the type arguments may have changed the index, may have
-  // grown the table, or may even have canonicalized this type.
-  canonical_types ^= cls.canonical_types();
-  if (canonical_types.IsNull()) {
-    canonical_types = empty_array().raw();
-  }
-  length = canonical_types.Length();
-  while (index < length) {
-    type ^= canonical_types.At(index);
-    if (type.IsNull()) {
-      break;
-    }
-    ASSERT(type.IsFinalized());
-    if (this->Equals(type)) {
-      ASSERT(type.IsCanonical());
-      return type.raw();
-    }
-    index++;
-  }
-
-  // The type needs to be added to the list. Grow the list if it is full.
-  if (index >= length) {
-    ASSERT((index == length) || ((index == 1) && (length == 0)));
-    const intptr_t new_length = (length > 64) ?
-        (length + 64) :
-        ((length == 0) ? 2 : (length * 2));
-    const Array& new_canonical_types = Array::Handle(
-        zone, Array::Grow(canonical_types, new_length, Heap::kOld));
-    cls.set_canonical_types(new_canonical_types);
-    canonical_types = new_canonical_types.raw();
-  }
-  canonical_types.SetAt(index, *this);
-  ASSERT(IsOld());
   ASSERT(type_args.IsNull() || type_args.IsOld());
-  SetCanonical();
-  return this->raw();
+
+  return cls.LookupOrAddCanonicalType(*this, index);
+}
+
+
+RawString* Type::EnumerateURIs() const {
+  if (IsDynamicType()) {
+    return Symbols::Empty().raw();
+  }
+  Zone* zone = Thread::Current()->zone();
+  GrowableHandlePtrArray<const String> pieces(zone, 6);
+  const Class& cls = Class::Handle(zone, type_class());
+  pieces.Add(Symbols::TwoSpaces());
+  pieces.Add(String::Handle(zone, cls.UserVisibleName()));
+  pieces.Add(Symbols::SpaceIsFromSpace());
+  const Library& library = Library::Handle(zone, cls.library());
+  pieces.Add(String::Handle(zone, library.url()));
+  pieces.Add(Symbols::NewLine());
+  const TypeArguments& type_args = TypeArguments::Handle(zone, arguments());
+  pieces.Add(String::Handle(zone, type_args.EnumerateURIs()));
+  return Symbols::FromConcatAll(pieces);
 }
 
 
@@ -15772,7 +16022,7 @@
 
 
 bool FunctionType::IsMalbounded() const {
-  if (!Isolate::Current()->flags().type_checks()) {
+  if (!Isolate::Current()->type_checks()) {
     return false;
   }
   if (raw_ptr()->error_ == LanguageError::null()) {
@@ -15792,7 +16042,7 @@
     return true;
   }
   ASSERT(type_error.kind() == Report::kMalboundedType);
-  return Isolate::Current()->flags().type_checks();
+  return Isolate::Current()->type_checks();
 }
 
 
@@ -16107,43 +16357,31 @@
     sig_fun.set_parameter_names(Array::Handle(zone, fun.parameter_names()));
     set_signature(sig_fun);
   }
-
-  // Canonicalizing the type arguments and the signature may have changed the
-  // index, may have grown the table, or may even have canonicalized this type.
-  canonical_types ^= scope_cls.canonical_types();
-  if (canonical_types.IsNull()) {
-    canonical_types = empty_array().raw();
-  }
-  length = canonical_types.Length();
-  while (index < length) {
-    type ^= canonical_types.At(index);
-    if (type.IsNull()) {
-      break;
-    }
-    ASSERT(type.IsFinalized());
-    if (this->Equals(type)) {
-      ASSERT(type.IsCanonical());
-      return type.raw();
-    }
-    index++;
-  }
-
-  // The type needs to be added to the list. Grow the list if it is full.
-  if (index >= length) {
-    ASSERT((index == length) || ((index == 1) && (length == 0)));
-    const intptr_t new_length = (length > 64) ?
-        (length + 64) :
-        ((length == 0) ? 2 : (length * 2));
-    const Array& new_canonical_types = Array::Handle(
-        zone, Array::Grow(canonical_types, new_length, Heap::kOld));
-    scope_cls.set_canonical_types(new_canonical_types);
-    canonical_types = new_canonical_types.raw();
-  }
-  canonical_types.SetAt(index, *this);
-  ASSERT(IsOld());
   ASSERT(type_args.IsNull() || type_args.IsOld());
-  SetCanonical();
-  return this->raw();
+
+  return scope_cls.LookupOrAddCanonicalType(*this, index);
+}
+
+
+RawString* FunctionType::EnumerateURIs() const {
+  Zone* zone = Thread::Current()->zone();
+  // The scope class and type arguments do not appear explicitly in the user
+  // visible name. The type arguments were used to instantiate the function type
+  // prior to this call.
+  const Function& sig_fun = Function::Handle(zone, signature());
+  AbstractType& type = AbstractType::Handle(zone);
+  const intptr_t num_params = sig_fun.NumParameters();
+  GrowableHandlePtrArray<const String> pieces(zone, num_params + 1);
+  for (intptr_t i = 0; i < num_params; i++) {
+    type = sig_fun.ParameterTypeAt(i);
+    pieces.Add(String::Handle(zone, type.EnumerateURIs()));
+  }
+  // Handle result type last, since it appears last in the user visible name.
+  type = sig_fun.result_type();
+  if (!type.IsDynamicType() && !type.IsVoidType()) {
+    pieces.Add(String::Handle(zone, type.EnumerateURIs()));
+  }
+  return Symbols::FromConcatAll(pieces);
 }
 
 
@@ -16350,6 +16588,11 @@
 }
 
 
+RawString* TypeRef::EnumerateURIs() const {
+  return Symbols::Empty().raw();  // Break cycle.
+}
+
+
 intptr_t TypeRef::Hash() const {
   // Do not calculate the hash of the referenced type to avoid divergence.
   const uint32_t result =
@@ -16565,6 +16808,22 @@
 }
 
 
+RawString* TypeParameter::EnumerateURIs() const {
+  Zone* zone = Thread::Current()->zone();
+  GrowableHandlePtrArray<const String> pieces(zone, 4);
+  pieces.Add(Symbols::TwoSpaces());
+  pieces.Add(String::Handle(zone, name()));
+  pieces.Add(Symbols::SpaceOfSpace());
+  const Class& cls = Class::Handle(zone, parameterized_class());
+  pieces.Add(String::Handle(zone, cls.UserVisibleName()));
+  pieces.Add(Symbols::SpaceIsFromSpace());
+  const Library& library = Library::Handle(zone, cls.library());
+  pieces.Add(String::Handle(zone, library.url()));
+  pieces.Add(Symbols::NewLine());
+  return Symbols::FromConcatAll(pieces);
+}
+
+
 intptr_t TypeParameter::Hash() const {
   ASSERT(IsFinalized());
   uint32_t result = Class::Handle(parameterized_class()).id();
@@ -16735,7 +16994,7 @@
     // (or instantiated) either.
     // Note that instantiator_type_arguments must have the final length, though.
   }
-  if ((Isolate::Current()->flags().type_checks()) &&
+  if ((Isolate::Current()->type_checks()) &&
       (bound_error != NULL) && bound_error->IsNull()) {
     AbstractType& upper_bound = AbstractType::Handle(bound());
     ASSERT(upper_bound.IsFinalized());
@@ -16817,6 +17076,12 @@
 }
 
 
+RawString* BoundedType::EnumerateURIs() const {
+  // The bound does not appear in the user visible name.
+  return AbstractType::Handle(type()).EnumerateURIs();
+}
+
+
 intptr_t BoundedType::Hash() const {
   uint32_t result = AbstractType::Handle(type()).Hash();
   // No need to include the hash of the bound, since the bound is defined by the
@@ -21059,23 +21324,6 @@
 }
 
 
-static intptr_t PrintOneStacktraceNoCode(Zone* zone,
-                                         GrowableArray<char*>* frame_strings,
-                                         const Function& function,
-                                         intptr_t frame_index) {
-  const Script& script = Script::Handle(zone, function.script());
-  const String& function_name =
-      String::Handle(zone, function.QualifiedUserVisibleName());
-  const String& url = String::Handle(zone, script.url());
-  char* chars = NULL;
-  chars = OS::SCreate(zone,
-      "#%-6" Pd " %s (%s)\n",
-      frame_index, function_name.ToCString(), url.ToCString());
-  frame_strings->Add(chars);
-  return strlen(chars);
-}
-
-
 const char* Stacktrace::ToCStringInternal(intptr_t* frame_index,
                                           intptr_t max_frames) const {
   Zone* zone = Thread::Current()->zone();
@@ -21088,7 +21336,7 @@
   for (intptr_t i = 0; (i < Length()) && (*frame_index < max_frames); i++) {
     function = FunctionAtFrame(i);
     if (function.IsNull()) {
-      // Check if null function object indicates a gap in a StackOverflow or
+      // Check for a null function, which indicates a gap in a StackOverflow or
       // OutOfMemory trace.
       if ((i < (Length() - 1)) &&
           (FunctionAtFrame(i + 1) != Function::null())) {
@@ -21098,48 +21346,29 @@
         OS::SNPrint(chars, truncated_len, "%s", kTruncated);
         frame_strings.Add(chars);
         total_len += truncated_len;
+        ASSERT(PcOffsetAtFrame(i) != Smi::null());
+        // To account for gap frames.
+        (*frame_index) += Smi::Value(PcOffsetAtFrame(i));
       }
     } else {
       code = CodeAtFrame(i);
       ASSERT(function.raw() == code.function());
       uword pc = code.EntryPoint() + Smi::Value(PcOffsetAtFrame(i));
-      if (code.is_optimized() && expand_inlined()) {
+      if (code.is_optimized() && expand_inlined() && !FLAG_precompiled_mode) {
         // Traverse inlined frames.
-        if (!FLAG_precompilation) {
-          for (InlinedFunctionsIterator it(code, pc);
-               !it.Done() && (*frame_index < max_frames); it.Advance()) {
-            function = it.function();
-            if (function.is_visible() || FLAG_show_invisible_frames) {
-              code = it.code();
-              ASSERT(function.raw() == code.function());
-              uword pc = it.pc();
-              ASSERT(pc != 0);
-              ASSERT(code.EntryPoint() <= pc);
-              ASSERT(pc < (code.EntryPoint() + code.Size()));
-              total_len += PrintOneStacktrace(
-                  zone, &frame_strings, pc, function, code, *frame_index);
-              (*frame_index)++;  // To account for inlined frames.
-            }
-          }
-        } else {
-          // Precompilation: we don't have deopt info, so we don't know the
-          // source position of inlined functions, but we can still name them.
-          intptr_t offset = Smi::Value(PcOffsetAtFrame(i));
-          // The PC of frames below the top frame is a call's return address,
-          // which can belong to a different inlining interval than the call.
-          intptr_t effective_offset = offset - 1;
-          GrowableArray<Function*> inlined_functions;
-          code.GetInlinedFunctionsAt(effective_offset, &inlined_functions);
-          ASSERT(inlined_functions.length() >= 1);  // At least the inliner.
-          for (intptr_t j = 0; j < inlined_functions.length(); j++) {
-            Function* inlined_function = inlined_functions[j];
-            ASSERT(inlined_function != NULL);
-            ASSERT(!inlined_function->IsNull());
-            if (inlined_function->is_visible() || FLAG_show_invisible_frames) {
-              total_len += PrintOneStacktraceNoCode(
-                  zone, &frame_strings, *inlined_function, *frame_index);
-              (*frame_index)++;
-            }
+        for (InlinedFunctionsIterator it(code, pc);
+             !it.Done() && (*frame_index < max_frames); it.Advance()) {
+          function = it.function();
+          if (function.is_visible() || FLAG_show_invisible_frames) {
+            code = it.code();
+            ASSERT(function.raw() == code.function());
+            uword pc = it.pc();
+            ASSERT(pc != 0);
+            ASSERT(code.EntryPoint() <= pc);
+            ASSERT(pc < (code.EntryPoint() + code.Size()));
+            total_len += PrintOneStacktrace(
+                zone, &frame_strings, pc, function, code, *frame_index);
+            (*frame_index)++;  // To account for inlined frames.
           }
         }
       } else {
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index ee8782a..8fafabc 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -585,13 +585,13 @@
     // are preserved as well.
     //
     // e.g.
-    //   private getter             - get:foo@6be832b
-    //   private constructor        - _MyClass@6b3832b.
-    //   private named constructor  - _MyClass@6b3832b.named
-    //   core impl class name shown - _OneByteString
+    //   private getter             -> get:foo@6be832b
+    //   private constructor        -> _MyClass@6b3832b.
+    //   private named constructor  -> _MyClass@6b3832b.named
+    //   core impl class name shown -> _OneByteString
     kInternalName = 0,
 
-    // Pretty names drop privacy suffixes, getter prefixes, and
+    // Scrubbed names drop privacy suffixes, getter prefixes, and
     // trailing dots on unnamed constructors.  These names are used in
     // the vm service.
     //
@@ -599,11 +599,11 @@
     //   get:foo@6be832b        -> foo
     //   _MyClass@6b3832b.      -> _MyClass
     //   _MyClass@6b3832b.named -> _MyClass.named
-    //   _OneByteString          -> _OneByteString (not remapped)
-    kPrettyName,
+    //   _OneByteString         -> _OneByteString (not remapped)
+    kScrubbedName,
 
     // User visible names are appropriate for reporting type errors
-    // directly to programmers.  The names have been "prettied" and
+    // directly to programmers.  The names have been scrubbed and
     // the names of core implementation classes are remapped to their
     // public interface names.
     //
@@ -611,7 +611,7 @@
     //   get:foo@6be832b        -> foo
     //   _MyClass@6b3832b.      -> _MyClass
     //   _MyClass@6b3832b.named -> _MyClass.named
-    //   _OneByteString          -> String (remapped)
+    //   _OneByteString         -> String (remapped)
     kUserVisibleName
   };
 
@@ -953,7 +953,7 @@
   }
 
   RawString* Name() const;
-  RawString* PrettyName() const;
+  RawString* ScrubbedName() const;
   RawString* UserVisibleName() const;
   bool IsInFullSnapshot() const;
 
@@ -1417,9 +1417,7 @@
   class IsAllocatedBit : public BitField<uint16_t, bool, kIsAllocatedBit, 1> {};
 
   void set_name(const String& value) const;
-  void set_pretty_name(const String& value) const;
   void set_user_name(const String& value) const;
-  RawString* GeneratePrettyName() const;
   RawString* GenerateUserVisibleName() const;
   void set_state_bits(intptr_t bits) const;
 
@@ -1490,6 +1488,15 @@
       TrailPtr bound_trail,
       Heap::Space space);
 
+  // Returns AbstractType::null() if type not found.
+  RawAbstractType* LookupCanonicalType(Zone* zone,
+                                       const AbstractType& type,
+                                       intptr_t* index) const;
+
+  // Returns canonical type. Thread safe.
+  RawAbstractType* LookupOrAddCanonicalType(const AbstractType& type,
+                                            intptr_t start_index) const;
+
   FINAL_HEAP_OBJECT_IMPLEMENTATION(Class, Object);
   friend class AbstractType;
   friend class Instance;
@@ -1549,12 +1556,6 @@
     return SubvectorName(0, Length(), kInternalName);
   }
 
-  // The name of this type argument vector, e.g. "<T, dynamic, List<T>, Smi>".
-  // Names of internal classes are not mapped to their public interfaces.
-  RawString* PrettyName() const {
-    return SubvectorName(0, Length(), kPrettyName);
-  }
-
   // The name of this type argument vector, e.g. "<T, dynamic, List<T>, int>".
   // Names of internal classes are mapped to their public interfaces.
   RawString* UserVisibleName() const {
@@ -1644,6 +1645,9 @@
   // Canonicalize only if instantiated, otherwise returns 'this'.
   RawTypeArguments* Canonicalize(TrailPtr trail = NULL) const;
 
+  // Returns a formatted list of occuring type arguments with their URI.
+  RawString* EnumerateURIs() const;
+
   // Return 'this' if this type argument vector is instantiated, i.e. if it does
   // not refer to type parameters. Otherwise, return a new type argument vector
   // where each reference to a type parameter is replaced with the corresponding
@@ -2108,11 +2112,13 @@
 class Function : public Object {
  public:
   RawString* name() const { return raw_ptr()->name_; }
-  RawString* PrettyName() const;
-  RawString* UserVisibleName() const;
-  RawString* QualifiedPrettyName() const;
-  RawString* QualifiedUserVisibleName() const;
-  const char* QualifiedUserVisibleNameCString() const;
+  RawString* UserVisibleName() const;  // Same as scrubbed name.
+  RawString* QualifiedScrubbedName() const {
+    return QualifiedName(kScrubbedName);
+  }
+  RawString* QualifiedUserVisibleName() const {
+    return QualifiedName(kUserVisibleName);
+  }
   virtual RawString* DictionaryName() const { return name(); }
 
   RawString* GetSource() const;
@@ -2136,12 +2142,6 @@
     return BuildSignature(instantiate, kInternalName, TypeArguments::Handle());
   }
 
-  RawString* PrettySignature() const {
-    const bool instantiate = false;
-    return BuildSignature(
-        instantiate, kPrettyName, TypeArguments::Handle());
-  }
-
   // Build a string of the form '(T, {b: B, c: C}) => R' representing the
   // user visible signature of the given function. In this example, T and R are
   // type parameters of class C, the owner of the function, also called the
@@ -2798,6 +2798,8 @@
 
   static RawFunction* New();
 
+  RawString* QualifiedName(NameVisibility name_visibility) const;
+
   void BuildSignatureParameters(
       bool instantiate,
       NameVisibility name_visibility,
@@ -2891,9 +2893,22 @@
 
 class Field : public Object {
  public:
+  RawField* Original() const;
+  void SetOriginal(const Field& value) const;
+  bool IsOriginal() const {
+    if (IsNull()) {
+      return true;
+    }
+    NoSafepointScope no_safepoint;
+    return !raw_ptr()->owner_->IsField();
+  }
+
+  // Returns a field cloned from 'this'. 'this' is set as the
+  // original field of result.
+  RawField* CloneFromOriginal() const;
+
   RawString* name() const { return raw_ptr()->name_; }
-  RawString* PrettyName() const;
-  RawString* UserVisibleName() const;
+  RawString* UserVisibleName() const;  // Same as scrubbed name.
   virtual RawString* DictionaryName() const { return name(); }
 
   bool is_static() const { return StaticBit::decode(raw_ptr()->kind_bits_); }
@@ -2903,6 +2918,7 @@
     return ReflectableBit::decode(raw_ptr()->kind_bits_);
   }
   void set_is_reflectable(bool value) const {
+    ASSERT(IsOriginal());
     set_kind_bits(ReflectableBit::update(value, raw_ptr()->kind_bits_));
   }
   bool is_double_initialized() const {
@@ -2912,6 +2928,7 @@
   // Marks fields that are initialized with a simple double constant.
   void set_is_double_initialized(bool value) const {
     ASSERT(Thread::Current()->IsMutatorThread());
+    ASSERT(IsOriginal());
     set_kind_bits(DoubleInitializedBit::update(value, raw_ptr()->kind_bits_));
   }
 
@@ -2923,10 +2940,10 @@
   inline void SetStaticValue(const Instance& value,
                              bool save_initial_value = false) const;
 
-  RawClass* owner() const;
-  RawClass* origin() const;  // Either mixin class, or same as owner().
-  RawScript* script() const;
-  RawObject* RawOwner() const { return raw_ptr()->owner_; }
+  RawClass* Owner() const;
+  RawClass* Origin() const;  // Either mixin class, or same as owner().
+  RawScript* Script() const;
+  RawObject* RawOwner() const;
 
   RawAbstractType* type() const  { return raw_ptr()->type_; }
   // Used by class finalizer, otherwise initialized in constructor.
@@ -2954,6 +2971,9 @@
   // Allocate new field object, clone values from this field. The
   // owner of the clone is new_owner.
   RawField* Clone(const Class& new_owner) const;
+  // Allocate new field object, clone values from this field. The
+  // original is specified.
+  RawField* Clone(const Field& original) const;
 
   static intptr_t instance_field_offset() {
     return OFFSET_OF(RawField, value_.offset_);
@@ -2971,6 +2991,7 @@
   }
   // Called by parser after allocating field.
   void set_has_initializer(bool has_initializer) const {
+    ASSERT(IsOriginal());
     ASSERT(Thread::Current()->IsMutatorThread());
     set_kind_bits(HasInitializerBit::update(has_initializer,
                                             raw_ptr()->kind_bits_));
@@ -3021,6 +3042,7 @@
   // Default 'true', set to false once optimizing compiler determines it should
   // be boxed.
   void set_is_unboxing_candidate(bool b) const {
+    ASSERT(IsOriginal());
     set_kind_bits(UnboxingCandidateBit::update(b, raw_ptr()->kind_bits_));
   }
 
@@ -4051,6 +4073,18 @@
   // Decode SLEB128 encoded integer. Update byte_index to the next integer.
   intptr_t DecodeInteger(intptr_t* byte_index) const;
 
+  TokenPosition TokenPositionForPCOffset(uword pc_offset) const;
+  RawFunction* FunctionForPCOffset(const Code& code,
+                                   const Function& function,
+                                   uword pc_offset) const;
+  RawScript* ScriptForPCOffset(const Code& code,
+                               const Function& function,
+                               uword pc_offset) const;
+
+  static void Dump(const CodeSourceMap& code_source_map,
+                   const Code& code,
+                   const Function& function);
+
   class Iterator : ValueObject {
    public:
     explicit Iterator(const CodeSourceMap& code_source_map)
@@ -4428,6 +4462,9 @@
   RawArray* GetInlinedIdToFunction() const;
   void SetInlinedIdToFunction(const Array& value) const;
 
+  RawArray* GetInlinedIdToTokenPos() const;
+  void SetInlinedIdToTokenPos(const Array& value) const;
+
   RawArray* GetInlinedCallerIdMap() const;
   void SetInlinedCallerIdMap(const Array& value) const;
 
@@ -4519,7 +4556,7 @@
   intptr_t GetDeoptIdForOsr(uword pc) const;
 
   RawString* Name() const;
-  RawString* PrettyName() const;
+  RawString* QualifiedName() const;
 
   int64_t compile_timestamp() const {
     return raw_ptr()->compile_timestamp_;
@@ -5319,16 +5356,19 @@
     return BuildName(kInternalName);
   }
 
-  virtual RawString* PrettyName() const {
-    return BuildName(kPrettyName);
-  }
-
   // The name of this type, including the names of its type arguments, if any.
   // Names of internal classes are mapped to their public interfaces.
   virtual RawString* UserVisibleName() const {
     return BuildName(kUserVisibleName);
   }
 
+  // Same as user visible name, but including the URI of each occuring type.
+  // Used to report errors involving types with identical names.
+  virtual RawString* UserVisibleNameWithURI() const;
+
+  // Returns a formatted list of occuring types with their URI.
+  virtual RawString* EnumerateURIs() const;
+
   virtual intptr_t Hash() const;
 
   // The name of this type's class, i.e. without the type argument names of this
@@ -5472,6 +5512,7 @@
       const Class& new_owner,
       TrailPtr trail = NULL) const;
   virtual RawAbstractType* Canonicalize(TrailPtr trail = NULL) const;
+  virtual RawString* EnumerateURIs() const;
 
   virtual intptr_t Hash() const;
 
@@ -5620,6 +5661,7 @@
       const Class& new_owner,
       TrailPtr trail = NULL) const;
   virtual RawAbstractType* Canonicalize(TrailPtr trail = NULL) const;
+  virtual RawString* EnumerateURIs() const;
 
   virtual intptr_t Hash() const;
 
@@ -5696,6 +5738,7 @@
       const Class& new_owner,
       TrailPtr trail = NULL) const;
   virtual RawAbstractType* Canonicalize(TrailPtr trail = NULL) const;
+  virtual RawString* EnumerateURIs() const;
 
   virtual intptr_t Hash() const;
 
@@ -5771,6 +5814,7 @@
   virtual RawAbstractType* Canonicalize(TrailPtr trail = NULL) const {
     return raw();
   }
+  virtual RawString* EnumerateURIs() const;
 
   virtual intptr_t Hash() const;
 
@@ -5857,6 +5901,7 @@
   virtual RawAbstractType* Canonicalize(TrailPtr trail = NULL) const {
     return raw();
   }
+  virtual RawString* EnumerateURIs() const;
 
   virtual intptr_t Hash() const;
 
@@ -6520,8 +6565,8 @@
   static RawString* ToLowerCase(const String& str,
                                 Heap::Space space = Heap::kNew);
 
-  static RawString* IdentifierPrettyName(const String& name);
-  static RawString* IdentifierPrettyNameRetainPrivate(const String& name);
+  static RawString* ScrubName(const String& name);
+  static RawString* ScrubNameRetainPrivate(const String& name);
 
   static bool EqualsIgnoringPrivateKey(const String& str1,
                                        const String& str2);
diff --git a/runtime/vm/object_service.cc b/runtime/vm/object_service.cc
index 54bd965..ba63134 100644
--- a/runtime/vm/object_service.cc
+++ b/runtime/vm/object_service.cc
@@ -84,9 +84,9 @@
   }
   AddCommonObjectProperties(&jsobj, "Class", ref);
   jsobj.AddFixedServiceId("classes/%" Pd "", id());
-  const String& user_name = String::Handle(PrettyName());
+  const String& scrubbed_name = String::Handle(ScrubbedName());
   const String& vm_name = String::Handle(Name());
-  AddNameProperties(&jsobj, user_name, vm_name);
+  AddNameProperties(&jsobj, scrubbed_name, vm_name);
   if (ref) {
     return;
   }
@@ -184,7 +184,7 @@
   ASSERT(table.Length() > 0);
   AddCommonObjectProperties(&jsobj, "TypeArguments", ref);
   jsobj.AddServiceId(*this);
-  const String& user_name = String::Handle(PrettyName());
+  const String& user_name = String::Handle(UserVisibleName());
   const String& vm_name = String::Handle(Name());
   AddNameProperties(&jsobj, user_name, vm_name);
   if (ref) {
@@ -270,7 +270,7 @@
   JSONObject jsobj(stream);
   AddCommonObjectProperties(&jsobj, "Function", ref);
   AddFunctionServiceId(jsobj, *this, cls);
-  const String& user_name = String::Handle(PrettyName());
+  const String& user_name = String::Handle(UserVisibleName());
   const String& vm_name = String::Handle(name());
   AddNameProperties(&jsobj, user_name, vm_name);
   const Function& parent = Function::Handle(parent_function());
@@ -334,14 +334,14 @@
 
 void Field::PrintJSONImpl(JSONStream* stream, bool ref) const {
   JSONObject jsobj(stream);
-  Class& cls = Class::Handle(owner());
+  Class& cls = Class::Handle(Owner());
   String& field_name = String::Handle(name());
   field_name = String::EncodeIRI(field_name);
   AddCommonObjectProperties(&jsobj, "Field", ref);
   jsobj.AddFixedServiceId("classes/%" Pd "/fields/%s",
                           cls.id(), field_name.ToCString());
 
-  const String& user_name = String::Handle(PrettyName());
+  const String& user_name = String::Handle(UserVisibleName());
   const String& vm_name = String::Handle(name());
   AddNameProperties(&jsobj, user_name, vm_name);
   if (cls.IsTopLevel()) {
@@ -382,8 +382,8 @@
   } else {
     jsobj.AddProperty("_guardLength", guarded_list_length());
   }
-  const Class& origin_cls = Class::Handle(origin());
-  const Script& script = Script::Handle(origin_cls.script());
+  const Class& origin_cls = Class::Handle(Origin());
+  const class Script& script = Script::Handle(origin_cls.script());
   if (!script.IsNull()) {
     jsobj.AddLocation(script, token_pos());
   }
@@ -481,9 +481,8 @@
   AddCommonObjectProperties(&jsobj, "Library", ref);
   jsobj.AddFixedServiceId("libraries/%" Pd "", id);
   const String& vm_name = String::Handle(name());
-  const String& user_name =
-      String::Handle(String::IdentifierPrettyName(vm_name));
-  AddNameProperties(&jsobj, user_name, vm_name);
+  const String& scrubbed_name = String::Handle(String::ScrubName(vm_name));
+  AddNameProperties(&jsobj, scrubbed_name, vm_name);
   const String& library_url = String::Handle(url());
   jsobj.AddPropertyStr("uri", library_url);
   if (ref) {
@@ -819,9 +818,9 @@
   jsobj.AddFixedServiceId("code/%" Px64"-%" Px "",
                           compile_timestamp(),
                           EntryPoint());
-  const String& user_name = String::Handle(PrettyName());
+  const String& qualified_name = String::Handle(QualifiedName());
   const String& vm_name = String::Handle(Name());
-  AddNameProperties(&jsobj, user_name, vm_name);
+  AddNameProperties(&jsobj, qualified_name, vm_name);
   const bool is_stub = IsStubCode() || IsAllocationStubCode();
   if (is_stub) {
     jsobj.AddProperty("kind", "Stub");
@@ -848,8 +847,9 @@
     JSONObject func(&jsobj, "function");
     func.AddProperty("type", "@Function");
     func.AddProperty("_kind", "Stub");
-    func.AddProperty("name", user_name.ToCString());
-    AddNameProperties(&func, user_name, vm_name);
+    ASSERT(qualified_name.Equals(vm_name));
+    func.AddProperty("name", vm_name.ToCString());
+    AddNameProperties(&func, vm_name, vm_name);
   }
   jsobj.AddPropertyF("_startAddress", "%" Px "", EntryPoint());
   jsobj.AddPropertyF("_endAddress", "%" Px "", EntryPoint() + Size());
@@ -1122,7 +1122,7 @@
   } else {
     jsobj.AddServiceId(*this);
   }
-  const String& user_name = String::Handle(PrettyName());
+  const String& user_name = String::Handle(UserVisibleName());
   const String& vm_name = String::Handle(Name());
   AddNameProperties(&jsobj, user_name, vm_name);
   if (ref) {
@@ -1149,7 +1149,7 @@
   } else {
     jsobj.AddServiceId(*this);
   }
-  const String& user_name = String::Handle(PrettyName());
+  const String& user_name = String::Handle(UserVisibleName());
   const String& vm_name = String::Handle(Name());
   AddNameProperties(&jsobj, user_name, vm_name);
   if (ref) {
@@ -1167,7 +1167,7 @@
   PrintSharedInstanceJSON(&jsobj, ref);
   jsobj.AddProperty("kind", "TypeRef");
   jsobj.AddServiceId(*this);
-  const String& user_name = String::Handle(PrettyName());
+  const String& user_name = String::Handle(UserVisibleName());
   const String& vm_name = String::Handle(Name());
   AddNameProperties(&jsobj, user_name, vm_name);
   if (ref) {
@@ -1182,7 +1182,7 @@
   PrintSharedInstanceJSON(&jsobj, ref);
   jsobj.AddProperty("kind", "TypeParameter");
   jsobj.AddServiceId(*this);
-  const String& user_name = String::Handle(PrettyName());
+  const String& user_name = String::Handle(UserVisibleName());
   const String& vm_name = String::Handle(Name());
   AddNameProperties(&jsobj, user_name, vm_name);
   const Class& param_cls = Class::Handle(parameterized_class());
@@ -1201,7 +1201,7 @@
   PrintSharedInstanceJSON(&jsobj, ref);
   jsobj.AddProperty("kind", "BoundedType");
   jsobj.AddServiceId(*this);
-  const String& user_name = String::Handle(PrettyName());
+  const String& user_name = String::Handle(UserVisibleName());
   const String& vm_name = String::Handle(Name());
   AddNameProperties(&jsobj, user_name, vm_name);
   if (ref) {
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index ae009ec..e793b9b 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -4034,7 +4034,11 @@
   EXPECT_NE(a_test3.SourceFingerprint(), a_test4.SourceFingerprint());
   EXPECT_NE(a_test4.SourceFingerprint(), a_test5.SourceFingerprint());
   EXPECT_EQ(a_test5.SourceFingerprint(), b_test5.SourceFingerprint());
-  EXPECT_NE(a_test6.SourceFingerprint(), b_test6.SourceFingerprint());
+  // Although a_test6's receiver type is different than b_test6's receiver type,
+  // the fingerprints are identical. The token stream does not reflect the
+  // receiver's type. This is not a problem, since we recognize functions
+  // of a given class and of a given name.
+  EXPECT_EQ(a_test6.SourceFingerprint(), b_test6.SourceFingerprint());
 }
 
 
@@ -4692,7 +4696,7 @@
 };
 
 
-VM_TEST_CASE(String_IdentifierPrettyName) {
+VM_TEST_CASE(String_ScrubName) {
   TestResult tests[] = {
     {"(dynamic, dynamic) => void", "(dynamic, dynamic) => void"},
     {"_List@915557746", "_List"},
@@ -4712,7 +4716,7 @@
   String& result = String::Handle();
   for (size_t i = 0; i < ARRAY_SIZE(tests); i++) {
     test = String::New(tests[i].in);
-    result = String::IdentifierPrettyName(test);
+    result = String::ScrubName(test);
     EXPECT_STREQ(tests[i].out, result.ToCString());
   }
 }
diff --git a/runtime/vm/os_thread.h b/runtime/vm/os_thread.h
index ce22b2b..2ca6a7c 100644
--- a/runtime/vm/os_thread.h
+++ b/runtime/vm/os_thread.h
@@ -267,7 +267,7 @@
   ~Mutex();
 
   void Lock();
-  bool TryLock();
+  bool TryLock();  // Returns false if lock is busy and locking failed.
   void Unlock();
 
 #if defined(DEBUG)
@@ -303,6 +303,7 @@
   Monitor();
   ~Monitor();
 
+  bool TryEnter();  // Returns false if lock is busy and locking failed.
   void Enter();
   void Exit();
 
diff --git a/runtime/vm/os_thread_android.cc b/runtime/vm/os_thread_android.cc
index c02fd9a..9b93cbe 100644
--- a/runtime/vm/os_thread_android.cc
+++ b/runtime/vm/os_thread_android.cc
@@ -336,6 +336,22 @@
 }
 
 
+bool Monitor::TryEnter() {
+  int result = pthread_mutex_trylock(data_.mutex());
+  // Return false if the lock is busy and locking failed.
+  if (result == EBUSY) {
+    return false;
+  }
+  ASSERT_PTHREAD_SUCCESS(result);  // Verify no other errors.
+#if defined(DEBUG)
+  // When running with assertions enabled we track the owner.
+  ASSERT(owner_ == OSThread::kInvalidThreadId);
+  owner_ = OSThread::GetCurrentThreadId();
+#endif  // defined(DEBUG)
+  return true;
+}
+
+
 void Monitor::Enter() {
   int result = pthread_mutex_lock(data_.mutex());
   VALIDATE_PTHREAD_RESULT(result);
diff --git a/runtime/vm/os_thread_linux.cc b/runtime/vm/os_thread_linux.cc
index f821233..a0e68f1 100644
--- a/runtime/vm/os_thread_linux.cc
+++ b/runtime/vm/os_thread_linux.cc
@@ -341,6 +341,22 @@
 }
 
 
+bool Monitor::TryEnter() {
+  int result = pthread_mutex_trylock(data_.mutex());
+  // Return false if the lock is busy and locking failed.
+  if (result == EBUSY) {
+    return false;
+  }
+  ASSERT_PTHREAD_SUCCESS(result);  // Verify no other errors.
+#if defined(DEBUG)
+  // When running with assertions enabled we track the owner.
+  ASSERT(owner_ == OSThread::kInvalidThreadId);
+  owner_ = OSThread::GetCurrentThreadId();
+#endif  // defined(DEBUG)
+  return true;
+}
+
+
 void Monitor::Enter() {
   int result = pthread_mutex_lock(data_.mutex());
   VALIDATE_PTHREAD_RESULT(result);
diff --git a/runtime/vm/os_thread_macos.cc b/runtime/vm/os_thread_macos.cc
index 1964f64..42dd360 100644
--- a/runtime/vm/os_thread_macos.cc
+++ b/runtime/vm/os_thread_macos.cc
@@ -335,6 +335,22 @@
 }
 
 
+bool Monitor::TryEnter() {
+  int result = pthread_mutex_trylock(data_.mutex());
+  // Return false if the lock is busy and locking failed.
+  if ((result == EBUSY) || (result == EDEADLK)) {
+    return false;
+  }
+  ASSERT_PTHREAD_SUCCESS(result);  // Verify no other errors.
+#if defined(DEBUG)
+  // When running with assertions enabled we track the owner.
+  ASSERT(owner_ == OSThread::kInvalidThreadId);
+  owner_ = OSThread::GetCurrentThreadId();
+#endif  // defined(DEBUG)
+  return true;
+}
+
+
 void Monitor::Enter() {
   int result = pthread_mutex_lock(data_.mutex());
   VALIDATE_PTHREAD_RESULT(result);
diff --git a/runtime/vm/os_thread_win.cc b/runtime/vm/os_thread_win.cc
index 7a29d0d..3802a16 100644
--- a/runtime/vm/os_thread_win.cc
+++ b/runtime/vm/os_thread_win.cc
@@ -305,6 +305,21 @@
 }
 
 
+bool Monitor::TryEnter() {
+  // Attempt to pass the semaphore but return immediately.
+  BOOL result = TryEnterCriticalSection(&data_.cs_);
+  if (!result) {
+    return false;
+  }
+#if defined(DEBUG)
+  // When running with assertions enabled we do track the owner.
+  ASSERT(owner_ == OSThread::kInvalidThreadId);
+  owner_ = OSThread::GetCurrentThreadId();
+#endif  // defined(DEBUG)
+  return true;
+}
+
+
 void Monitor::Enter() {
   EnterCriticalSection(&data_.cs_);
 
diff --git a/runtime/vm/pages.cc b/runtime/vm/pages.cc
index ff0fa53..177b091 100644
--- a/runtime/vm/pages.cc
+++ b/runtime/vm/pages.cc
@@ -29,21 +29,14 @@
             "Print free list statistics before a GC");
 DEFINE_FLAG(bool, print_free_list_after_gc, false,
             "Print free list statistics after a GC");
-DEFINE_FLAG(bool, collect_code, true,
-            "Attempt to GC infrequently used code.");
 DEFINE_FLAG(int, code_collection_interval_in_us, 30000000,
             "Time between attempts to collect unused code.");
 DEFINE_FLAG(bool, log_code_drop, false,
             "Emit a log message when pointers to unused code are dropped.");
 DEFINE_FLAG(bool, always_drop_code, false,
             "Always try to drop code if the function's usage counter is >= 0");
-#if defined(TARGET_ARCH_MIPS) || defined(TARGET_ARCH_ARM64)
-DEFINE_FLAG(bool, concurrent_sweep, false,
-            "Concurrent sweep for old generation.");
-#else  // TARGET_ARCH_MIPS || TARGET_ARCH_ARM64
 DEFINE_FLAG(bool, concurrent_sweep, true,
             "Concurrent sweep for old generation.");
-#endif  // TARGET_ARCH_MIPS || TARGET_ARCH_ARM64
 DEFINE_FLAG(bool, log_growth, false, "Log PageSpace growth policy decisions.");
 
 HeapPage* HeapPage::Initialize(VirtualMemory* memory, PageType type) {
diff --git a/runtime/vm/pages.h b/runtime/vm/pages.h
index 008b7cd..12b193f 100644
--- a/runtime/vm/pages.h
+++ b/runtime/vm/pages.h
@@ -15,7 +15,6 @@
 
 namespace dart {
 
-DECLARE_FLAG(bool, collect_code);
 DECLARE_FLAG(bool, log_code_drop);
 DECLARE_FLAG(bool, always_drop_code);
 DECLARE_FLAG(bool, write_protect_code);
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 9571669..78ca6a5 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -41,11 +41,8 @@
 namespace dart {
 
 DEFINE_FLAG(bool, enable_debug_break, false, "Allow use of break \"message\".");
-DEFINE_FLAG(bool, load_deferred_eagerly, false,
-    "Load deferred libraries eagerly.");
 DEFINE_FLAG(bool, trace_parser, false, "Trace parser operations.");
 DEFINE_FLAG(bool, warn_mixin_typedef, true, "Warning on legacy mixin typedef.");
-DEFINE_FLAG(bool, link_natives_lazily, false, "Link native calls lazily");
 DEFINE_FLAG(bool, conditional_directives, false,
     "Enable conditional directives");
 DEFINE_FLAG(bool, warn_super, false,
@@ -53,8 +50,8 @@
 DEFINE_FLAG(bool, await_is_keyword, false,
     "await and yield are treated as proper keywords in synchronous code.");
 
-DECLARE_FLAG(bool, load_deferred_eagerly);
 DECLARE_FLAG(bool, profile_vm);
+DECLARE_FLAG(bool, trace_service);
 
 // Quick access to the current thread, isolate and zone.
 #define T (thread())
@@ -166,7 +163,7 @@
       return;
     }
   }
-  guarded_fields_->Add(field);
+  guarded_fields_->Add(&Field::ZoneHandle(Z, field->Original()));
 }
 
 
@@ -1081,8 +1078,8 @@
     Thread* thread = Thread::Current();
     StackZone stack_zone(thread);
     Zone* zone = stack_zone.GetZone();
-    const Class& owner_class = Class::Handle(zone, meta_data.owner());
-    const Script& script = Script::Handle(zone, meta_data.script());
+    const Class& owner_class = Class::Handle(zone, meta_data.Owner());
+    const Script& script = Script::Handle(zone, meta_data.Script());
     const TokenPosition token_pos = meta_data.token_pos();
     // Parsing metadata can involve following paths in the parser that are
     // normally used for expressions and assume current_function is non-null,
@@ -1222,10 +1219,10 @@
   String& init_name = String::Handle(zone,
       Symbols::FromConcat(Symbols::InitPrefix(), field_name));
 
-  const Script& script = Script::Handle(zone, field.script());
-  Object& initializer_owner = Object::Handle(field.owner());
+  const Script& script = Script::Handle(zone, field.Script());
+  Object& initializer_owner = Object::Handle(field.Owner());
   initializer_owner =
-      PatchClass::New(Class::Handle(field.owner()), script);
+      PatchClass::New(Class::Handle(field.Owner()), script);
 
   const Function& initializer = Function::ZoneHandle(zone,
       Function::New(init_name,
@@ -2552,7 +2549,8 @@
       if (initializers->NodeAt(i)->IsStoreInstanceFieldNode()) {
         StoreInstanceFieldNode* initializer =
             initializers->NodeAt(i)->AsStoreInstanceFieldNode();
-        if (initializer->field().raw() == field.raw()) {
+        ASSERT(field.IsOriginal());
+        if (initializer->field().Original() == field.raw()) {
           found = true;
           break;
         }
@@ -2570,13 +2568,13 @@
   // Only use this function if the initialized field originates
   // from a different class. We need to save and restore current
   // class, library, and token stream (script).
-  ASSERT(current_class().raw() != field.origin());
+  ASSERT(current_class().raw() != field.Origin());
   const Class& saved_class = Class::Handle(Z, current_class().raw());
   const Library& saved_library = Library::Handle(Z, library().raw());
   const Script& saved_script = Script::Handle(Z, script().raw());
   const TokenPosition saved_token_pos = TokenPos();
 
-  set_current_class(Class::Handle(Z, field.origin()));
+  set_current_class(Class::Handle(Z, field.Origin()));
   set_library(Library::Handle(Z, current_class().library()));
   SetScript(Script::Handle(Z, current_class().script()), field.token_pos());
 
@@ -2624,7 +2622,7 @@
         initialized_fields->Add(&field);
       }
       AstNode* init_expr = NULL;
-      if (current_class().raw() != field.origin()) {
+      if (current_class().raw() != field.Origin()) {
         init_expr = ParseExternalInitializedField(field);
       } else {
         SetPosition(field.token_pos());
@@ -2959,6 +2957,22 @@
 }
 
 
+// Returns a zone allocated string.
+static char* DumpPendingFunctions(
+    Zone* zone,
+    const GrowableObjectArray& pending_functions) {
+  ASSERT(zone != NULL);
+  char* result = OS::SCreate(zone, "Pending Functions:\n");
+  for (intptr_t i = 0; i < pending_functions.Length(); i++) {
+    const Function& func =
+        Function::Handle(zone, Function::RawCast(pending_functions.At(i)));
+    const String& fname = String::Handle(zone, func.UserVisibleName());
+    result = OS::SCreate(zone, "%s%" Pd ": %s\n", result, i, fname.ToCString());
+  }
+  return result;
+}
+
+
 void Parser::CheckRecursiveInvocation() {
   const GrowableObjectArray& pending_functions =
       GrowableObjectArray::Handle(Z, T->pending_functions());
@@ -2967,7 +2981,16 @@
     if (pending_functions.At(i) == current_function().raw()) {
       const String& fname =
           String::Handle(Z, current_function().UserVisibleName());
-      ReportError("circular dependency for function %s", fname.ToCString());
+      if (FLAG_trace_service) {
+        const char* pending_function_dump =
+            DumpPendingFunctions(Z, pending_functions);
+        ASSERT(pending_function_dump != NULL);
+        ReportError("circular dependency for function %s\n%s",
+                    fname.ToCString(),
+                    pending_function_dump);
+      } else {
+        ReportError("circular dependency for function %s", fname.ToCString());
+      }
     }
   }
   ASSERT(!unregister_pending_function_);
@@ -3278,7 +3301,7 @@
     // Populate function scope with the formal parameters.
     AddFormalParamsToScope(&params, current_block_->scope);
 
-    if (I->flags().type_checks() &&
+    if (I->type_checks() &&
         (current_block_->scope->function_level() > 0)) {
       // We are parsing, but not compiling, a local function.
       // The instantiator may be required at run time for generic type checks.
@@ -4609,7 +4632,7 @@
   SkipMetadata();
   ExpectToken(Token::kENUM);
 
-  const String& enum_name = String::Handle(Z, cls.PrettyName());
+  const String& enum_name = String::Handle(Z, cls.ScrubbedName());
   ClassDesc enum_members(Z, cls, enum_name, false, cls.token_pos());
 
   // Add instance field 'final int index'.
@@ -4707,7 +4730,7 @@
     // For the user-visible name of the enumeration value, we need to
     // unmangle private names.
     if (enum_ident->CharAt(0) == '_') {
-      *enum_ident = String::IdentifierPrettyName(*enum_ident);
+      *enum_ident = String::ScrubName(*enum_ident);
     }
     enum_value_name = Symbols::FromConcat(name_prefix, *enum_ident);
     enum_names.Add(enum_value_name, Heap::kOld);
@@ -5799,7 +5822,7 @@
           : String::Cast(valueNode->AsLiteralNode()->literal());
       // Call the embedder to supply us with the environment.
       const String& env_value =
-          String::Handle(Api::CallEnvironmentCallback(T, key));
+          String::Handle(Api::GetEnvironmentValue(T, key));
       if (!env_value.IsNull() && env_value.Equals(value)) {
         condition_triggered = true;
         url_literal = conditional_url_literal;
@@ -7466,7 +7489,7 @@
   bool is_final = (CurrentToken() == Token::kFINAL);
   bool is_const = (CurrentToken() == Token::kCONST);
   const AbstractType& type = AbstractType::ZoneHandle(Z,
-      ParseConstFinalVarOrType(I->flags().type_checks() ?
+      ParseConstFinalVarOrType(I->type_checks() ?
           ClassFinalizer::kCanonicalize : ClassFinalizer::kIgnore));
   if (!IsIdentifier()) {
     ReportError("identifier expected");
@@ -8534,7 +8557,7 @@
     // position, which is inside the loop body.
     new_loop_var = true;
     loop_var_type = ParseConstFinalVarOrType(
-       I->flags().type_checks() ? ClassFinalizer::kCanonicalize :
+       I->type_checks() ? ClassFinalizer::kCanonicalize :
                                   ClassFinalizer::kIgnore);
   }
   TokenPosition loop_var_pos = TokenPos();
@@ -8828,7 +8851,7 @@
     // position, which is inside the loop body.
     new_loop_var = true;
     loop_var_type = ParseConstFinalVarOrType(
-        I->flags().type_checks() ? ClassFinalizer::kCanonicalize :
+        I->type_checks() ? ClassFinalizer::kCanonicalize :
                                    ClassFinalizer::kIgnore);
     loop_var_name = ExpectIdentifier("variable name expected");
   }
@@ -9047,7 +9070,7 @@
   ConsumeToken();  // Consume assert keyword.
   ExpectToken(Token::kLPAREN);
   const TokenPosition condition_pos = TokenPos();
-  if (!I->flags().asserts()) {
+  if (!I->asserts()) {
     SkipExpr();
     ExpectToken(Token::kRPAREN);
     return NULL;
@@ -10686,7 +10709,7 @@
     } else if (original->IsLoadStaticFieldNode()) {
       name = original->AsLoadStaticFieldNode()->field().name();
       target_cls = &Class::Handle(Z,
-          original->AsLoadStaticFieldNode()->field().owner());
+          original->AsLoadStaticFieldNode()->field().Owner());
     } else if ((left_ident != NULL) &&
                (original->IsLiteralNode() ||
                 original->IsLoadLocalNode())) {
@@ -11184,7 +11207,7 @@
   }
   // The field is initialized.
   ASSERT(field.is_static());
-  const Class& field_owner = Class::ZoneHandle(Z, field.owner());
+  const Class& field_owner = Class::ZoneHandle(Z, field.Owner());
   const String& field_name = String::ZoneHandle(Z, field.name());
   const String& getter_name =
       String::Handle(Z, Field::GetterSymbol(field_name));
@@ -12027,7 +12050,7 @@
 StaticGetterNode* Parser::RunStaticFieldInitializer(
     const Field& field, TokenPosition field_ref_pos) {
   ASSERT(field.is_static());
-  const Class& field_owner = Class::ZoneHandle(Z, field.owner());
+  const Class& field_owner = Class::ZoneHandle(Z, field.Owner());
   const String& field_name = String::ZoneHandle(Z, field.name());
   const String& getter_name =
       String::Handle(Z, Field::GetterSymbol(field_name));
@@ -12654,7 +12677,7 @@
                     "include a type variable");
       }
     } else {
-      if (I->flags().error_on_bad_type()) {
+      if (I->error_on_bad_type()) {
         ReportError(type_pos,
                     "a list literal takes one type argument specifying "
                     "the element type");
@@ -12677,7 +12700,7 @@
     while (CurrentToken() != Token::kRBRACK) {
       const TokenPosition element_pos = TokenPos();
       AstNode* element = ParseExpr(is_const, kConsumeCascades);
-      if (I->flags().type_checks() &&
+      if (I->type_checks() &&
           !is_const &&
           !element_type.IsDynamicType()) {
         element = new(Z) AssignableNode(element_pos,
@@ -12708,7 +12731,7 @@
       // Arguments have been evaluated to a literal value already.
       ASSERT(elem->IsLiteralNode());
       ASSERT(!is_top_level_);  // We cannot check unresolved types.
-      if (I->flags().type_checks() &&
+      if (I->type_checks() &&
           !element_type.IsDynamicType() &&
           (!elem->AsLiteralNode()->literal().IsNull() &&
            !elem->AsLiteralNode()->literal().IsInstanceOf(
@@ -12860,7 +12883,7 @@
                     "include a type variable");
       }
     } else {
-      if (I->flags().error_on_bad_type()) {
+      if (I->error_on_bad_type()) {
         ReportError(type_pos,
                     "a map literal takes two type arguments specifying "
                     "the key type and the value type");
@@ -12879,7 +12902,7 @@
     const bool saved_mode = SetAllowFunctionLiterals(true);
     const TokenPosition key_pos = TokenPos();
     AstNode* key = ParseExpr(is_const, kConsumeCascades);
-    if (I->flags().type_checks() &&
+    if (I->type_checks() &&
         !is_const &&
         !key_type.IsDynamicType()) {
       key = new(Z) AssignableNode(
@@ -12902,7 +12925,7 @@
     const TokenPosition value_pos = TokenPos();
     AstNode* value = ParseExpr(is_const, kConsumeCascades);
     SetAllowFunctionLiterals(saved_mode);
-    if (I->flags().type_checks() &&
+    if (I->type_checks() &&
         !is_const &&
         !value_type.IsDynamicType()) {
       value = new(Z) AssignableNode(
@@ -12934,7 +12957,7 @@
       // Arguments have been evaluated to a literal value already.
       ASSERT(arg->IsLiteralNode());
       ASSERT(!is_top_level_);  // We cannot check unresolved types.
-      if (I->flags().type_checks()) {
+      if (I->type_checks()) {
         if ((i % 2) == 0) {
           // Check key type.
           arg_type = key_type.raw();
@@ -13436,7 +13459,7 @@
         }
         return ThrowTypeError(redirect_type.token_pos(), redirect_type);
       }
-      if (I->flags().type_checks() &&
+      if (I->type_checks() &&
               !redirect_type.IsSubtypeOf(type, NULL, NULL, Heap::kOld)) {
         // Additional type checking of the result is necessary.
         type_bound = type.raw();
@@ -14345,11 +14368,6 @@
 
 namespace dart {
 
-DEFINE_FLAG(bool, load_deferred_eagerly, false,
-    "Load deferred libraries eagerly.");
-DEFINE_FLAG(bool, link_natives_lazily, false, "Link native calls lazily");
-
-
 void ParsedFunction::AddToGuardedFields(const Field* field) const {
   UNREACHABLE();
 }
diff --git a/runtime/vm/port.cc b/runtime/vm/port.cc
index 6af2ff8..a57b93f 100644
--- a/runtime/vm/port.cc
+++ b/runtime/vm/port.cc
@@ -313,7 +313,7 @@
   Object& msg_handler = Object::Handle();
   {
     JSONArray ports(&jsobj, "ports");
-    MutexLocker ml(mutex_);
+    SafepointMutexLocker ml(mutex_);
     for (intptr_t i = 0; i < capacity_; i++) {
       if (map_[i].handler == handler) {
         if (map_[i].state == kLivePort) {
diff --git a/runtime/vm/precompiler.cc b/runtime/vm/precompiler.cc
index ce5ca5e..2f876e0 100644
--- a/runtime/vm/precompiler.cc
+++ b/runtime/vm/precompiler.cc
@@ -49,9 +49,6 @@
 #define Z (zone())
 
 
-DEFINE_FLAG(bool, collect_dynamic_function_names, false,
-    "In precompilation collects all dynamic function names in order to"
-    " identify unique targets");
 DEFINE_FLAG(bool, print_unique_targets, false, "Print unique dynaic targets");
 DEFINE_FLAG(bool, trace_precompiler, false, "Trace precompiler.");
 DEFINE_FLAG(int, max_speculative_inlining_attempts, 1,
@@ -69,9 +66,7 @@
 DECLARE_FLAG(bool, trace_bailout);
 DECLARE_FLAG(bool, use_inlining);
 DECLARE_FLAG(bool, verify_compiler);
-DECLARE_FLAG(bool, precompilation);
 DECLARE_FLAG(bool, huge_method_cutoff_in_code_size);
-DECLARE_FLAG(bool, load_deferred_eagerly);
 DECLARE_FLAG(bool, trace_failed_optimization_attempts);
 DECLARE_FLAG(bool, trace_inlining_intervals);
 DECLARE_FLAG(bool, trace_irregexp);
@@ -576,6 +571,34 @@
     type = function.ParameterTypeAt(i);
     AddType(type);
   }
+  Code& code = Code::Handle(Z, function.CurrentCode());
+  if (code.IsNull()) {
+    ASSERT(function.kind() == RawFunction::kSignatureFunction);
+  } else {
+    const ExceptionHandlers& handlers =
+        ExceptionHandlers::Handle(Z, code.exception_handlers());
+    if (!handlers.IsNull()) {
+      Array& types = Array::Handle(Z);
+      for (intptr_t i = 0; i < handlers.num_entries(); i++) {
+        types = handlers.GetHandledTypes(i);
+        if (!types.IsNull()) {
+          for (intptr_t j = 0; j < types.Length(); j++) {
+            type ^= types.At(j);
+            AddType(type);
+          }
+        }
+      }
+    }
+  }
+  // A function can always be inlined and have only a nested local function
+  // remain.
+  const Function& parent = Function::Handle(Z, function.parent_function());
+  if (!parent.IsNull()) {
+    AddTypesOf(parent);
+  }
+  // A class may have all functions inlined except a local function.
+  const Class& owner = Class::Handle(Z, function.Owner());
+  AddTypesOf(owner);
 }
 
 
@@ -609,6 +632,13 @@
     AbstractType& type = AbstractType::Handle(Z);
     type = TypeRef::Cast(abstype).type();
     AddType(type);
+  } else if (abstype.IsTypeParameter()) {
+    const AbstractType& type =
+        AbstractType::Handle(Z, TypeParameter::Cast(abstype).bound());
+    AddType(type);
+    const Class& cls =
+        Class::Handle(Z, TypeParameter::Cast(abstype).parameterized_class());
+    AddTypesOf(cls);
   }
 }
 
@@ -1889,7 +1919,7 @@
 // If optimized_result_code is not NULL then it is caller's responsibility
 // to install code.
 bool PrecompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) {
-  ASSERT(FLAG_precompilation);
+  ASSERT(FLAG_precompiled_mode);
   const Function& function = parsed_function()->function();
   if (optimized() && !function.IsOptimizable()) {
     return false;
@@ -1971,6 +2001,8 @@
       // Maps inline_id_to_function[inline_id] -> function. Top scope
       // function has inline_id 0. The map is populated by the inliner.
       GrowableArray<const Function*> inline_id_to_function;
+      // Token position where inlining occured.
+      GrowableArray<TokenPosition> inline_id_to_token_pos;
       // For a given inlining-id(index) specifies the caller's inlining-id.
       GrowableArray<intptr_t> caller_inline_id;
       // Collect all instance fields that are loaded in the graph and
@@ -1983,6 +2015,7 @@
                                   "OptimizationPasses");
 #endif  // !PRODUCT
         inline_id_to_function.Add(&function);
+        inline_id_to_token_pos.Add(function.token_pos());
         // Top scope function has no caller (-1).
         caller_inline_id.Add(-1);
         CSTAT_TIMER_SCOPE(thread(), graphoptimizer_timer);
@@ -2026,6 +2059,7 @@
 
           FlowGraphInliner inliner(flow_graph,
                                    &inline_id_to_function,
+                                   &inline_id_to_token_pos,
                                    &caller_inline_id,
                                    use_speculative_inlining,
                                    &inlining_black_list);
@@ -2322,6 +2356,7 @@
       FlowGraphCompiler graph_compiler(&assembler, flow_graph,
                                        *parsed_function(), optimized(),
                                        inline_id_to_function,
+                                       inline_id_to_token_pos,
                                        caller_inline_id);
       {
         CSTAT_TIMER_SCOPE(thread(), graphcompiler_timer);
@@ -2404,7 +2439,7 @@
                                           const Function& function,
                                           bool optimized) {
   // Check that we optimize, except if the function is not optimizable.
-  ASSERT(FLAG_precompilation);
+  ASSERT(FLAG_precompiled_mode);
   ASSERT(!function.IsOptimizable() || optimized);
   ASSERT(!function.HasCode());
   LongJumpScope jump;
@@ -2501,7 +2536,7 @@
   CompilationPipeline* pipeline =
       CompilationPipeline::New(thread->zone(), function);
 
-  ASSERT(FLAG_precompilation);
+  ASSERT(FLAG_precompiled_mode);
   const bool optimized = function.IsOptimizable();  // False for natives.
   return PrecompileFunctionHelper(pipeline, function, optimized);
 }
diff --git a/runtime/vm/profiler.h b/runtime/vm/profiler.h
index e4f6c8d..0b1207f 100644
--- a/runtime/vm/profiler.h
+++ b/runtime/vm/profiler.h
@@ -54,7 +54,6 @@
 
  private:
   static bool initialized_;
-  static Monitor* monitor_;
 
   static SampleBuffer* sample_buffer_;
 
diff --git a/runtime/vm/profiler_service.cc b/runtime/vm/profiler_service.cc
index 8152884..3de17c8 100644
--- a/runtime/vm/profiler_service.cc
+++ b/runtime/vm/profiler_service.cc
@@ -553,17 +553,15 @@
     function = table->GetUnknown();
   } else if (kind() == kDartCode) {
     ASSERT(!code_.IsNull());
+    const String& name = String::Handle(code_.QualifiedName());
     const Object& obj = Object::Handle(code_.owner());
     if (obj.IsFunction()) {
-      const String& user_name = String::Handle(code_.PrettyName());
       function = table->LookupOrAdd(Function::Cast(obj));
-      SetName(user_name.ToCString());
     } else {
       // A stub.
-      const String& user_name = String::Handle(code_.PrettyName());
-      function = table->AddStub(start(), user_name.ToCString());
-      SetName(user_name.ToCString());
+      function = table->AddStub(start(), name.ToCString());
     }
+    SetName(name.ToCString());
   } else if (kind() == kNativeCode) {
     if (name() == NULL) {
       // Lazily set generated name.
diff --git a/runtime/vm/profiler_test.cc b/runtime/vm/profiler_test.cc
index 55149b2..f9ae241 100644
--- a/runtime/vm/profiler_test.cc
+++ b/runtime/vm/profiler_test.cc
@@ -15,7 +15,6 @@
 
 #ifndef PRODUCT
 
-DECLARE_FLAG(bool, background_compilation);
 DECLARE_FLAG(bool, profile_vm);
 DECLARE_FLAG(int, max_profile_depth);
 
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 76d49ed..c30823f 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -424,6 +424,9 @@
   bool IsScript() {
     return ((GetClassId() == kScriptCid));
   }
+  bool IsField() {
+    return ((GetClassId() == kFieldCid));
+  }
   bool IsFunction() {
     return ((GetClassId() == kFunctionCid));
   }
@@ -881,7 +884,7 @@
   RawObject** from() { return reinterpret_cast<RawObject**>(&ptr()->name_); }
   RawString* name_;
   RawObject* owner_;  // Class or patch class or mixin class
-                      // where this field is defined.
+                      // where this field is defined or original field.
   RawAbstractType* type_;
   union {
     RawInstance* static_value_;  // Value for static fields.
@@ -1052,7 +1055,8 @@
     kInlinedIntervalsIndex = 0,
     kInlinedIdToFunctionIndex = 1,
     kInlinedCallerIdMapIndex = 2,
-    kInlinedMetadataSize = 3,
+    kInlinedIdToTokenPosIndex = 3,
+    kInlinedMetadataSize = 4,
   };
 
   RAW_HEAP_OBJECT_IMPLEMENTATION(Code);
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index 6b9d728..ed22fa2 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -12,9 +12,6 @@
 
 namespace dart {
 
-DECLARE_FLAG(int, optimization_counter_threshold);
-DECLARE_FLAG(bool, use_field_guards);
-
 #define NEW_OBJECT(type)                                                       \
   ((kind == Snapshot::kFull) ? reader->New##type() : type::New())
 
diff --git a/runtime/vm/redundancy_elimination.cc b/runtime/vm/redundancy_elimination.cc
index 266abdf..adc1319 100644
--- a/runtime/vm/redundancy_elimination.cc
+++ b/runtime/vm/redundancy_elimination.cc
@@ -19,9 +19,6 @@
 DEFINE_FLAG(bool, trace_load_optimization, false,
     "Print live sets for load optimization pass.");
 
-DECLARE_FLAG(bool, fields_may_be_reset);
-DECLARE_FLAG(bool, precompilation);
-
 // Quick access to the current zone.
 #define Z (zone())
 
@@ -484,12 +481,13 @@
   }
 
   bool SameField(const Place* other) const {
-    return (kind() == kField) ? (field().raw() == other->field().raw())
-                              : (offset_in_bytes_ == other->offset_in_bytes_);
+    return (kind() == kField) ?
+        (field().Original() == other->field().Original()) :
+        (offset_in_bytes_ == other->offset_in_bytes_);
   }
 
   intptr_t FieldHashcode() const {
-    return (kind() == kField) ? reinterpret_cast<intptr_t>(field().raw())
+    return (kind() == kField) ? reinterpret_cast<intptr_t>(field().Original())
                               : offset_in_bytes_;
   }
 
@@ -1430,7 +1428,7 @@
 
 void LICM::OptimisticallySpecializeSmiPhis() {
   if (!flow_graph()->function().allows_hoisting_check_class() ||
-      FLAG_precompilation) {
+      FLAG_precompiled_mode) {
     // Do not hoist any: Either deoptimized on a hoisted check,
     // or compiling precompiled code where we can't do optimistic
     // hoisting of checks.
@@ -3088,6 +3086,8 @@
 // Add a field/offset to the list of fields if it is not yet present there.
 static bool AddSlot(ZoneGrowableArray<const Object*>* slots,
                     const Object& slot) {
+  ASSERT(slot.IsSmi() || slot.IsField());
+  ASSERT(!slot.IsField() || Field::Cast(slot).IsOriginal());
   for (intptr_t i = 0; i < slots->length(); i++) {
     if ((*slots)[i]->raw() == slot.raw()) {
       return false;
@@ -3284,7 +3284,7 @@
     StoreInstanceFieldInstr* store = use->instruction()->AsStoreInstanceField();
     if ((store != NULL) && (store->instance()->definition() == alloc)) {
       if (!store->field().IsNull()) {
-        AddSlot(slots, store->field());
+        AddSlot(slots, Field::ZoneHandle(Z, store->field().Original()));
       } else {
         AddSlot(slots, Smi::ZoneHandle(Z, Smi::New(store->offset_in_bytes())));
       }
diff --git a/runtime/vm/regexp.cc b/runtime/vm/regexp.cc
index 7cf9710..e49c3d8 100644
--- a/runtime/vm/regexp.cc
+++ b/runtime/vm/regexp.cc
@@ -19,8 +19,6 @@
 namespace dart {
 
 DECLARE_FLAG(bool, trace_irregexp);
-DEFINE_FLAG(bool, interpret_irregexp, false,
-            "Use irregexp bytecode interpreter");
 
 // Default to generating optimized regexp code.
 static const bool kRegexpOptimization = true;
diff --git a/runtime/vm/regexp_assembler.cc b/runtime/vm/regexp_assembler.cc
index 9e01f35..c916c70 100644
--- a/runtime/vm/regexp_assembler.cc
+++ b/runtime/vm/regexp_assembler.cc
@@ -4,10 +4,23 @@
 
 #include "vm/regexp_assembler.h"
 
+#include "vm/flags.h"
 #include "vm/regexp.h"
 
 namespace dart {
 
+BlockLabel::BlockLabel()
+    : block_(NULL),
+      is_bound_(false),
+      is_linked_(false),
+      pos_(-1) {
+  if (!FLAG_interpret_irregexp) {
+    // Only needed by the compiled IR backend.
+    block_ = new JoinEntryInstr(-1, -1);
+  }
+}
+
+
 RegExpMacroAssembler::RegExpMacroAssembler(Zone* zone)
   : slow_safe_compiler_(false),
     global_mode_(NOT_GLOBAL),
diff --git a/runtime/vm/regexp_assembler.h b/runtime/vm/regexp_assembler.h
index 5d0ee47..efd53c5 100644
--- a/runtime/vm/regexp_assembler.h
+++ b/runtime/vm/regexp_assembler.h
@@ -19,11 +19,7 @@
 class BlockLabel : public ValueObject {
   // Used by the IR assembler.
  public:
-  BlockLabel()
-    : block_(new JoinEntryInstr(-1, -1)),
-      is_bound_(false),
-      is_linked_(false),
-      pos_(-1) { }
+  BlockLabel();
 
   JoinEntryInstr* block() const { return block_; }
 
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index f75291d..b7ac721 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -12,6 +12,7 @@
 #include "vm/coverage.h"
 #include "vm/cpu.h"
 #include "vm/dart_api_impl.h"
+#include "vm/dart_api_state.h"
 #include "vm/dart_entry.h"
 #include "vm/debugger.h"
 #include "vm/isolate.h"
@@ -20,6 +21,7 @@
 #include "vm/message_handler.h"
 #include "vm/native_entry.h"
 #include "vm/native_arguments.h"
+#include "vm/native_symbol.h"
 #include "vm/object.h"
 #include "vm/object_graph.h"
 #include "vm/object_id_ring.h"
@@ -996,6 +998,10 @@
     OS::PrintErr("  Connect to Observatory at %s to debug.\n",
                  ServiceIsolate::server_address());
   }
+  const Error& err = Error::Handle(Thread::Current()->sticky_error());
+  if (!err.IsNull()) {
+    OS::PrintErr("%s\n", err.ToErrorCString());
+  }
 }
 
 
@@ -3463,6 +3469,99 @@
 }
 
 
+static const MethodParameter* get_persistent_handles_params[] = {
+  ISOLATE_PARAMETER,
+  NULL,
+};
+
+
+template<typename T>
+class PersistentHandleVisitor : public HandleVisitor {
+ public:
+  PersistentHandleVisitor(Thread* thread, JSONArray* handles)
+      : HandleVisitor(thread),
+        handles_(handles) {
+    ASSERT(handles_ != NULL);
+  }
+
+  void Append(PersistentHandle* persistent_handle) {
+    JSONObject obj(handles_);
+    obj.AddProperty("type", "_PersistentHandle");
+    const Object& object = Object::Handle(persistent_handle->raw());
+    obj.AddProperty("object", object);
+  }
+
+  void Append(FinalizablePersistentHandle* weak_persistent_handle) {
+    JSONObject obj(handles_);
+    obj.AddProperty("type", "_WeakPersistentHandle");
+    const Object& object =
+        Object::Handle(weak_persistent_handle->raw());
+    obj.AddProperty("object", object);
+    obj.AddPropertyF(
+        "peer",
+        "0x%" Px "",
+        reinterpret_cast<uintptr_t>(weak_persistent_handle->peer()));
+    obj.AddPropertyF(
+        "callbackAddress",
+        "0x%" Px "",
+        reinterpret_cast<uintptr_t>(weak_persistent_handle->callback()));
+    // Attempt to include a native symbol name.
+    char* name = NativeSymbolResolver::LookupSymbolName(
+        reinterpret_cast<uintptr_t>(weak_persistent_handle->callback()),
+        NULL);
+    obj.AddProperty("callbackSymbolName",
+                    (name == NULL) ? "" : name);
+    if (name != NULL) {
+      NativeSymbolResolver::FreeSymbolName(name);
+    }
+    obj.AddPropertyF("externalSize",
+                     "%" Pd "",
+                     weak_persistent_handle->external_size());
+  }
+
+ protected:
+  virtual void VisitHandle(uword addr) {
+    T* handle = reinterpret_cast<T*>(addr);
+    Append(handle);
+  }
+
+  JSONArray* handles_;
+};
+
+
+static bool GetPersistentHandles(Thread* thread, JSONStream* js) {
+  Isolate* isolate = thread->isolate();
+  ASSERT(isolate != NULL);
+
+  ApiState* api_state = isolate->api_state();
+  ASSERT(api_state != NULL);
+
+  {
+    JSONObject obj(js);
+    obj.AddProperty("type", "_PersistentHandles");
+    // Persistent handles.
+    {
+      JSONArray persistent_handles(&obj, "persistentHandles");
+      PersistentHandles& handles = api_state->persistent_handles();
+      PersistentHandleVisitor<PersistentHandle> visitor(
+          thread, &persistent_handles);
+      handles.Visit(&visitor);
+    }
+    // Weak persistent handles.
+    {
+      JSONArray weak_persistent_handles(&obj, "weakPersistentHandles");
+      FinalizablePersistentHandles& handles =
+          api_state->weak_persistent_handles();
+      PersistentHandleVisitor<FinalizablePersistentHandle> visitor(
+          thread, &weak_persistent_handles);
+      handles.VisitHandles(&visitor);
+    }
+  }
+
+  return true;
+}
+
+
 static const MethodParameter* get_ports_params[] = {
   RUNNABLE_ISOLATE_PARAMETER,
   NULL,
@@ -3934,6 +4033,8 @@
     get_object_params },
   { "_getObjectByAddress", GetObjectByAddress,
     get_object_by_address_params },
+  { "_getPersistentHandles", GetPersistentHandles,
+      get_persistent_handles_params, },
   { "_getPorts", GetPorts,
     get_ports_params },
   { "_getReachableSize", GetReachableSize,
diff --git a/runtime/vm/service_isolate.cc b/runtime/vm/service_isolate.cc
index 3d6207a..86c8aab 100644
--- a/runtime/vm/service_isolate.cc
+++ b/runtime/vm/service_isolate.cc
@@ -320,9 +320,8 @@
       return;
     }
 
-    Isolate::Flags default_flags;
     Dart_IsolateFlags api_flags;
-    default_flags.CopyTo(&api_flags);
+    Isolate::FlagsInitialize(&api_flags);
 
     isolate =
         reinterpret_cast<Isolate*>(create_callback(ServiceIsolate::kName,
diff --git a/runtime/vm/service_test.cc b/runtime/vm/service_test.cc
index de6cf73..b211fb7 100644
--- a/runtime/vm/service_test.cc
+++ b/runtime/vm/service_test.cc
@@ -440,6 +440,81 @@
 }
 
 
+
+static void WeakHandleFinalizer(void* isolate_callback_data,
+                                Dart_WeakPersistentHandle handle,
+                                void* peer) {
+}
+
+
+TEST_CASE(Service_PersistentHandles) {
+  const char* kScript =
+    "var port;\n"  // Set to our mock port by C++.
+    "\n"
+    "class A {\n"
+    "  var a;\n"
+    "}\n"
+    "var global = new A();\n"
+    "main() {\n"
+    "  return global;\n"
+    "}";
+
+  Isolate* isolate = thread->isolate();
+  isolate->set_is_runnable(true);
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+  Library& vmlib = Library::Handle();
+  vmlib ^= Api::UnwrapHandle(lib);
+  EXPECT(!vmlib.IsNull());
+  Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
+  EXPECT_VALID(result);
+
+  // Create a persistent handle to global.
+  Dart_PersistentHandle persistent_handle = Dart_NewPersistentHandle(result);
+
+  // Create a weak persistent handle to global.
+  Dart_WeakPersistentHandle weak_persistent_handle =
+      Dart_NewWeakPersistentHandle(result,
+                                   reinterpret_cast<void*>(0xdeadbeef),
+                                   128,
+                                   WeakHandleFinalizer);
+
+  // Build a mock message handler and wrap it in a dart port.
+  ServiceTestMessageHandler handler;
+  Dart_Port port_id = PortMap::CreatePort(&handler);
+  Dart_Handle port = Api::NewHandle(thread, SendPort::New(port_id));
+  EXPECT_VALID(port);
+  EXPECT_VALID(Dart_SetField(lib, NewString("port"), port));
+
+  Array& service_msg = Array::Handle();
+
+  // Get persistent handles.
+  service_msg = Eval(lib, "[0, port, '0', '_getPersistentHandles', [], []]");
+  Service::HandleIsolateMessage(isolate, service_msg);
+  EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
+  // Look for a heart beat.
+  EXPECT_SUBSTRING("\"type\":\"_PersistentHandles\"", handler.msg());
+  EXPECT_SUBSTRING("\"peer\":\"0xdeadbeef\"", handler.msg());
+  EXPECT_SUBSTRING("\"name\":\"A\"", handler.msg());
+  EXPECT_SUBSTRING("\"externalSize\":\"128\"", handler.msg());
+
+  // Delete persistent handles.
+  Dart_DeletePersistentHandle(persistent_handle);
+  Dart_DeleteWeakPersistentHandle(Dart_CurrentIsolate(),
+                                  weak_persistent_handle);
+
+  // Get persistent handles (again).
+  service_msg = Eval(lib, "[0, port, '0', '_getPersistentHandles', [], []]");
+  Service::HandleIsolateMessage(isolate, service_msg);
+  EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
+  EXPECT_SUBSTRING("\"type\":\"_PersistentHandles\"", handler.msg());
+  // Verify that old persistent handles are not present.
+  EXPECT_NOTSUBSTRING("\"peer\":\"0xdeadbeef\"", handler.msg());
+  EXPECT_NOTSUBSTRING("\"name\":\"A\"", handler.msg());
+  EXPECT_NOTSUBSTRING("\"externalSize\":\"128\"", handler.msg());
+}
+
+
 TEST_CASE(Service_Address) {
   const char* kScript =
       "var port;\n"  // Set to our mock port by C++.
diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc
index bbfa73b..e5d06c8 100644
--- a/runtime/vm/simulator_arm.cc
+++ b/runtime/vm/simulator_arm.cc
@@ -269,7 +269,7 @@
                                        bool is_optimized,
                                        bool is_inlined) {
   const Script& script = Script::Handle(function.script());
-  const String& func_name = String::Handle(function.QualifiedUserVisibleName());
+  const String& func_name = String::Handle(function.QualifiedScrubbedName());
   const String& url = String::Handle(script.url());
   intptr_t line = -1;
   intptr_t column = -1;
diff --git a/runtime/vm/simulator_arm64.cc b/runtime/vm/simulator_arm64.cc
index 7916d18..a19311d 100644
--- a/runtime/vm/simulator_arm64.cc
+++ b/runtime/vm/simulator_arm64.cc
@@ -287,7 +287,7 @@
                                        bool is_optimized,
                                        bool is_inlined) {
   const Script& script = Script::Handle(function.script());
-  const String& func_name = String::Handle(function.QualifiedUserVisibleName());
+  const String& func_name = String::Handle(function.QualifiedScrubbedName());
   const String& url = String::Handle(script.url());
   intptr_t line = -1;
   intptr_t column = -1;
@@ -1223,18 +1223,18 @@
 }
 
 
-intptr_t Simulator::ReadExclusiveW(uword addr, Instr* instr) {
+intptr_t Simulator::ReadExclusiveX(uword addr, Instr* instr) {
   MutexLocker ml(exclusive_access_lock_);
   SetExclusiveAccess(addr);
-  return ReadW(addr, instr);
+  return ReadX(addr, instr);
 }
 
 
-intptr_t Simulator::WriteExclusiveW(uword addr, intptr_t value, Instr* instr) {
+intptr_t Simulator::WriteExclusiveX(uword addr, intptr_t value, Instr* instr) {
   MutexLocker ml(exclusive_access_lock_);
   bool write_allowed = HasExclusiveAccessAndOpen(addr);
   if (write_allowed) {
-    WriteW(addr, value, instr);
+    WriteX(addr, value, instr);
     return 0;  // Success.
   }
   return 1;  // Failure.
@@ -1749,6 +1749,12 @@
 
 
 void Simulator::DecodeSystem(Instr* instr) {
+  if (instr->InstructionBits() == CLREX) {
+    // Format(instr, "clrex");
+    ClearExclusive();
+    return;
+  }
+
   if ((instr->Bits(0, 8) == 0x1f) && (instr->Bits(12, 4) == 2) &&
       (instr->Bits(16, 3) == 3) && (instr->Bits(19, 2) == 0) &&
       (instr->Bit(21) == 0)) {
@@ -2164,6 +2170,36 @@
 }
 
 
+void Simulator::DecodeLoadStoreExclusive(Instr* instr) {
+  if ((instr->Bit(23) != 0) ||
+      (instr->Bit(21) != 0) ||
+      (instr->Bit(15) != 0)) {
+    UNIMPLEMENTED();
+  }
+  const int32_t size = instr->Bits(30, 2);
+  if (size != 3) {
+    UNIMPLEMENTED();
+  }
+
+  const Register rs = instr->RsField();
+  const Register rn = instr->RnField();
+  const Register rt = instr->RtField();
+  const bool is_load = instr->Bit(22) == 1;
+  if (is_load) {
+    // Format(instr, "ldxr 'rt, 'rn");
+    const int64_t addr = get_register(rn, R31IsSP);
+    intptr_t value = ReadExclusiveX(addr, instr);
+    set_register(instr, rt, value, R31IsSP);
+  } else {
+    // Format(instr, "stxr 'rs, 'rt, 'rn");
+    uword value = get_register(rt, R31IsSP);
+    uword addr = get_register(rn, R31IsSP);
+    intptr_t status = WriteExclusiveX(addr, value, instr);
+    set_register(instr, rs, status, R31IsSP);
+  }
+}
+
+
 void Simulator::DecodeLoadStore(Instr* instr) {
   if (instr->IsLoadStoreRegOp()) {
     DecodeLoadStoreReg(instr);
@@ -2171,6 +2207,8 @@
     DecodeLoadStoreRegPair(instr);
   } else if (instr->IsLoadRegLiteralOp()) {
     DecodeLoadRegLiteral(instr);
+  } else if (instr->IsLoadStoreExclusiveOp()) {
+    DecodeLoadStoreExclusive(instr);
   } else {
     UnimplementedInstruction(instr);
   }
diff --git a/runtime/vm/simulator_arm64.h b/runtime/vm/simulator_arm64.h
index d395f6b..bf3572c 100644
--- a/runtime/vm/simulator_arm64.h
+++ b/runtime/vm/simulator_arm64.h
@@ -208,8 +208,8 @@
 
   // Synchronization primitives support.
   void ClearExclusive();
-  intptr_t ReadExclusiveW(uword addr, Instr* instr);
-  intptr_t WriteExclusiveW(uword addr, intptr_t value, Instr* instr);
+  intptr_t ReadExclusiveX(uword addr, Instr* instr);
+  intptr_t WriteExclusiveX(uword addr, intptr_t value, Instr* instr);
 
   // Set access to given address to 'exclusive state' for current thread.
   static void SetExclusiveAccess(uword addr);
diff --git a/runtime/vm/simulator_mips.cc b/runtime/vm/simulator_mips.cc
index 2b03da8..074fc8c 100644
--- a/runtime/vm/simulator_mips.cc
+++ b/runtime/vm/simulator_mips.cc
@@ -280,7 +280,7 @@
                                        bool is_optimized,
                                        bool is_inlined) {
   const Script& script = Script::Handle(function.script());
-  const String& func_name = String::Handle(function.QualifiedUserVisibleName());
+  const String& func_name = String::Handle(function.QualifiedScrubbedName());
   const String& url = String::Handle(script.url());
   intptr_t line = -1;
   intptr_t column = -1;
@@ -1173,9 +1173,9 @@
   bool write_allowed = HasExclusiveAccessAndOpen(addr);
   if (write_allowed) {
     WriteW(addr, value, instr);
-    return 0;  // Success.
+    return 1;  // Success.
   }
-  return 1;  // Failure.
+  return 0;  // Failure.
 }
 
 
@@ -2169,6 +2169,19 @@
       set_register(instr->RtField(), instr->UImmField() << 16);
       break;
     }
+    case LL: {
+      // Format(instr, "ll 'rt, 'imms('rs)");
+      int32_t base_val = get_register(instr->RsField());
+      int32_t imm_val = instr->SImmField();
+      uword addr = base_val + imm_val;
+      if (Simulator::IsIllegalAddress(addr)) {
+        HandleIllegalAccess(addr, instr);
+      } else {
+        int32_t res = ReadExclusiveW(addr, instr);
+        set_register(instr->RtField(), res);
+      }
+      break;
+    }
     case LW: {
       // Format(instr, "lw 'rt, 'imms('rs)");
       int32_t base_val = get_register(instr->RsField());
@@ -2214,6 +2227,20 @@
       }
       break;
     }
+    case SC: {
+      // Format(instr, "sc 'rt, 'imms('rs)");
+      int32_t rt_val = get_register(instr->RtField());
+      int32_t base_val = get_register(instr->RsField());
+      int32_t imm_val = instr->SImmField();
+      uword addr = base_val + imm_val;
+      if (Simulator::IsIllegalAddress(addr)) {
+        HandleIllegalAccess(addr, instr);
+      } else {
+        intptr_t status = WriteExclusiveW(addr, rt_val, instr);
+        set_register(instr->RtField(), status);
+      }
+      break;
+    }
     case SLTI: {
       // Format(instr, "slti 'rt, 'rs, 'imms");
       int32_t rs_val = get_register(instr->RsField());
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index bf02cba..294a90b 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -28,9 +28,6 @@
 
 namespace dart {
 
-DECLARE_FLAG(bool, use_field_guards);
-
-
 static const int kNumVmIsolateSnapshotReferences = 32 * KB;
 static const int kNumInitialReferencesInFullSnapshot = 160 * KB;
 static const int kNumInitialReferences = 64;
diff --git a/runtime/vm/snapshot_test.cc b/runtime/vm/snapshot_test.cc
index 35d3728..26dccc8 100644
--- a/runtime/vm/snapshot_test.cc
+++ b/runtime/vm/snapshot_test.cc
@@ -18,8 +18,6 @@
 
 namespace dart {
 
-DECLARE_FLAG(bool, enable_type_checks);
-DECLARE_FLAG(bool, load_deferred_eagerly);
 DECLARE_FLAG(bool, concurrent_sweep);
 
 // Check if serialized and deserialized objects are equal.
@@ -1001,6 +999,7 @@
 }
 
 
+#if !defined(PRODUCT)  // Uses deferred loading.
 UNIT_TEST_CASE(CanonicalizationInScriptSnapshots) {
   const char* kScriptChars =
       "\n"
@@ -1106,6 +1105,7 @@
   free(script_snapshot);
   free(full_snapshot);
 }
+#endif
 
 
 static void IterateScripts(const Library& lib) {
@@ -1469,9 +1469,6 @@
 }
 
 
-#endif  // !PRODUCT
-
-
 UNIT_TEST_CASE(ScriptSnapshot1) {
   const char* kScriptChars =
     "class _SimpleNumEnumerable<T extends num> {"
@@ -1581,7 +1578,7 @@
 
   // Force creation of snapshot in production mode.
   bool saved_enable_type_checks_mode = FLAG_enable_type_checks;
-  FLAG_enable_type_checks = false;
+  NOT_IN_PRODUCT(FLAG_enable_type_checks = false);
   bool saved_load_deferred_eagerly_mode = FLAG_load_deferred_eagerly;
   FLAG_load_deferred_eagerly = true;
   bool saved_concurrent_sweep_mode = FLAG_concurrent_sweep;
@@ -1633,7 +1630,7 @@
   }
 
   // Continue in originally saved mode.
-  FLAG_enable_type_checks = saved_enable_type_checks_mode;
+  NOT_IN_PRODUCT(FLAG_enable_type_checks = saved_enable_type_checks_mode);
   FLAG_load_deferred_eagerly = saved_load_deferred_eagerly_mode;
 
   {
@@ -1666,6 +1663,9 @@
 }
 
 
+#endif  // !PRODUCT
+
+
 TEST_CASE(IntArrayMessage) {
   StackZone zone(Thread::Current());
   uint8_t* buffer = NULL;
diff --git a/runtime/vm/stub_code_arm.cc b/runtime/vm/stub_code_arm.cc
index 77b6685..6b8812e 100644
--- a/runtime/vm/stub_code_arm.cc
+++ b/runtime/vm/stub_code_arm.cc
@@ -26,7 +26,6 @@
 DEFINE_FLAG(bool, use_slow_path, false,
     "Set to true for debugging & verifying the slow paths.");
 DECLARE_FLAG(bool, trace_optimized_ic_calls);
-DECLARE_FLAG(int, optimization_counter_threshold);
 
 // Input parameters:
 //   LR : return address.
diff --git a/runtime/vm/stub_code_arm64.cc b/runtime/vm/stub_code_arm64.cc
index c0648d4..61c3a4b 100644
--- a/runtime/vm/stub_code_arm64.cc
+++ b/runtime/vm/stub_code_arm64.cc
@@ -25,7 +25,6 @@
 DEFINE_FLAG(bool, use_slow_path, false,
     "Set to true for debugging & verifying the slow paths.");
 DECLARE_FLAG(bool, trace_optimized_ic_calls);
-DECLARE_FLAG(int, optimization_counter_threshold);
 
 // Input parameters:
 //   LR : return address.
@@ -1040,8 +1039,17 @@
   __ Push(R2);
   __ Push(R3);
 
-  __ orri(R2, TMP, Immediate(1 << RawObject::kRememberedBit));
-  __ StoreFieldToOffset(R2, R0, Object::tags_offset());
+  // Atomically set the remembered bit of the object header.
+  ASSERT(Object::tags_offset() == 0);
+  __ sub(R3, R0, Operand(kHeapObjectTag));
+  // R3: Untagged address of header word (ldxr/stxr do not support offsets).
+  Label retry;
+  __ Bind(&retry);
+  __ ldxr(R2, R3);
+  __ orri(R2, R2, Immediate(1 << RawObject::kRememberedBit));
+  __ stxr(R1, R2, R3);
+  __ cmp(R1, Operand(1));
+  __ b(&retry, EQ);
 
   // Load the StoreBuffer block out of the thread. Then load top_ out of the
   // StoreBufferBlock and add the address to the pointers_.
diff --git a/runtime/vm/stub_code_ia32.cc b/runtime/vm/stub_code_ia32.cc
index e79efba..640f0ec 100644
--- a/runtime/vm/stub_code_ia32.cc
+++ b/runtime/vm/stub_code_ia32.cc
@@ -27,7 +27,6 @@
 DEFINE_FLAG(bool, use_slow_path, false,
     "Set to true for debugging & verifying the slow paths.");
 DECLARE_FLAG(bool, trace_optimized_ic_calls);
-DECLARE_FLAG(int, optimization_counter_threshold);
 
 #define INT32_SIZEOF(x) static_cast<int32_t>(sizeof(x))
 
diff --git a/runtime/vm/stub_code_mips.cc b/runtime/vm/stub_code_mips.cc
index 8d1b252..b4965c33 100644
--- a/runtime/vm/stub_code_mips.cc
+++ b/runtime/vm/stub_code_mips.cc
@@ -25,7 +25,6 @@
 DEFINE_FLAG(bool, use_slow_path, false,
     "Set to true for debugging & verifying the slow paths.");
 DECLARE_FLAG(bool, trace_optimized_ic_calls);
-DECLARE_FLAG(int, optimization_counter_threshold);
 
 // Input parameters:
 //   RA : return address.
@@ -1066,8 +1065,14 @@
   __ Ret();
 
   __ Bind(&add_to_buffer);
+  // Atomically set the remembered bit of the object header.
+  Label retry;
+  __ Bind(&retry);
+  __ ll(T2, FieldAddress(T0, Object::tags_offset()));
   __ ori(T2, T2, Immediate(1 << RawObject::kRememberedBit));
-  __ sw(T2, FieldAddress(T0, Object::tags_offset()));
+  __ sc(T2, FieldAddress(T0, Object::tags_offset()));
+  // T2 = 1 on success, 0 on failure.
+  __ beq(T2, ZR, &retry);
 
   // Load the StoreBuffer block out of the thread. Then load top_ out of the
   // StoreBufferBlock and add the address to the pointers_.
diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc
index ace6744..b33ee01 100644
--- a/runtime/vm/stub_code_x64.cc
+++ b/runtime/vm/stub_code_x64.cc
@@ -26,7 +26,6 @@
 DEFINE_FLAG(bool, use_slow_path, false,
     "Set to true for debugging & verifying the slow paths.");
 DECLARE_FLAG(bool, trace_optimized_ic_calls);
-DECLARE_FLAG(int, optimization_counter_threshold);
 
 // Input parameters:
 //   RSP : points to return address.
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 39d6b23..9390ee1 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -316,6 +316,9 @@
   V(ColonSpace, ": ")                                                          \
   V(RParenArrow, ") => ")                                                      \
   V(SpaceExtendsSpace, " extends ")                                            \
+  V(SpaceWhereNewLine, " where\n")                                             \
+  V(SpaceIsFromSpace, " is from ")                                             \
+  V(SpaceOfSpace, " of ")                                                      \
   V(SwitchExpr, ":switch_expr")                                                \
   V(TwoNewlines, "\n\n")                                                       \
   V(TwoSpaces, "  ")                                                           \
@@ -401,6 +404,8 @@
   V(ConstructorClosurePrefix, "new#")                                          \
   V(_runExtension, "_runExtension")                                            \
   V(_runPendingImmediateCallback, "_runPendingImmediateCallback")              \
+  V(DartLibrary, "dart.library.")                                              \
+  V(DartLibraryMirrors, "dart.library.mirrors")                                \
 
 
 // Contains a list of frequently used strings in a canonicalized form. This
@@ -421,7 +426,7 @@
 
     kKwTableStart,  // First keyword at kKwTableStart + 1.
 
-#define DEFINE_KEYWORD_SYMBOL_INDEX(t, s, p, a)                            \
+#define DEFINE_KEYWORD_SYMBOL_INDEX(t, s, p, a)                                \
     t##Id,
     DART_KEYWORD_LIST(DEFINE_KEYWORD_SYMBOL_INDEX)
 #undef DEFINE_KEYWORD_SYMBOL_INDEX
diff --git a/runtime/vm/thread_pool.cc b/runtime/vm/thread_pool.cc
index 19c0a4d..b281d5c 100644
--- a/runtime/vm/thread_pool.cc
+++ b/runtime/vm/thread_pool.cc
@@ -383,11 +383,11 @@
     task_ = NULL;
 
     // Release monitor while handling the task.
-    monitor_.Exit();
+    ml.Exit();
     task->Run();
     ASSERT(Isolate::Current() == NULL);
     delete task;
-    monitor_.Enter();
+    ml.Enter();
 
     ASSERT(task_ == NULL);
     if (IsDone()) {
diff --git a/runtime/vm/thread_test.cc b/runtime/vm/thread_test.cc
index 95ea190..a20d7a4 100644
--- a/runtime/vm/thread_test.cc
+++ b/runtime/vm/thread_test.cc
@@ -45,6 +45,8 @@
   Monitor* monitor = new Monitor();
   monitor->Enter();
   monitor->Exit();
+  EXPECT_EQ(true, monitor->TryEnter());
+  monitor->Exit();
 
   const int kNumAttempts = 5;
   int attempts = 0;
diff --git a/runtime/vm/token_position.h b/runtime/vm/token_position.h
index b36d58a..c964716 100644
--- a/runtime/vm/token_position.h
+++ b/runtime/vm/token_position.h
@@ -38,7 +38,11 @@
     V(ControlFlow, -7)                                                         \
     V(Context, -8)                                                             \
     V(MethodExtractor, -9)                                                     \
-    V(Last, -10)   // Always keep this at the end.
+    V(DeferredSlowPath, -10)                                                   \
+    V(DeferredDeoptInfo, -11)                                                  \
+    V(DartCodePrologue, -12)                                                   \
+    V(DartCodeEpilogue, -13)                                                   \
+    V(Last, -14)   // Always keep this at the end.
 
 // A token position representing a debug safe source (real) position,
 // non-debug safe source (synthetic) positions, or a classifying value used
diff --git a/runtime/vm/vm_sources.gypi b/runtime/vm/vm_sources.gypi
index f21951b..ee08b98 100644
--- a/runtime/vm/vm_sources.gypi
+++ b/runtime/vm/vm_sources.gypi
@@ -185,8 +185,6 @@
     'flow_graph_compiler_x64.cc',
     'flow_graph_inliner.cc',
     'flow_graph_inliner.h',
-    'flow_graph_optimizer.cc',
-    'flow_graph_optimizer.h',
     'flow_graph_range_analysis.cc',
     'flow_graph_range_analysis.h',
     'flow_graph_range_analysis_test.cc',
@@ -250,6 +248,8 @@
     'isolate.cc',
     'isolate.h',
     'isolate_test.cc',
+    'jit_optimizer.cc',
+    'jit_optimizer.h',
     'json_stream.h',
     'json_stream.cc',
     'json_test.cc',
diff --git a/runtime/vm/weak_code.cc b/runtime/vm/weak_code.cc
index 0c5cca2..eb04d1f 100644
--- a/runtime/vm/weak_code.cc
+++ b/runtime/vm/weak_code.cc
@@ -13,8 +13,6 @@
 
 namespace dart {
 
-DECLARE_FLAG(bool, precompilation);
-
 bool WeakCodeReferences::HasCodes() const {
   return !array_.IsNull() && (array_.Length() > 0);
 }
@@ -68,7 +66,7 @@
   if (code_objects.IsNull()) {
     return;
   }
-  ASSERT(!FLAG_precompilation);
+  ASSERT(!FLAG_precompiled_mode);
   UpdateArrayTo(Object::null_array());
   // Disable all code on stack.
   Code& code = Code::Handle();
diff --git a/sdk/lib/html/html_common/conversions_dartium.dart b/sdk/lib/html/html_common/conversions_dartium.dart
index 3c35817..90fe55d 100644
--- a/sdk/lib/html/html_common/conversions_dartium.dart
+++ b/sdk/lib/html/html_common/conversions_dartium.dart
@@ -103,7 +103,7 @@
 class _ReturnedDictionary {
   Map _values;
 
-  noSuchMethod(InvocationMirror invocation) {
+  noSuchMethod(Invocation invocation) {
     var key = MirrorSystem.getName(invocation.memberName);
     if (invocation.isGetter) {
       return _values[key];
@@ -115,7 +115,7 @@
 
   Map get toMap => _values;
 
-  _ReturnedDictionary(Map value): _values = value;
+  _ReturnedDictionary(Map value): _values = value != null ? value : {};
 }
 
 // Helper function to wrapped a returned dictionary from blink to a Dart looking
diff --git a/sdk/lib/io/http.dart b/sdk/lib/io/http.dart
index cfdcc10..c63d28b 100644
--- a/sdk/lib/io/http.dart
+++ b/sdk/lib/io/http.dart
@@ -108,8 +108,8 @@
  *       var key =
  *           Platform.script.resolve('certificates/server_key.pem')
  *           .toFilePath();
- *       context.useCertificateChainSync(chain);
- *       context.usePrivateKeySync(key, password: 'dartdart');
+ *       context.useCertificateChain(chain);
+ *       context.usePrivateKey(key, password: 'dartdart');
  *
  *       HttpServer
  *           .bindSecure(InternetAddress.ANY_IP_V6,
diff --git a/sdk/lib/io/security_context.dart b/sdk/lib/io/security_context.dart
index fc9defd..86dfc96 100644
--- a/sdk/lib/io/security_context.dart
+++ b/sdk/lib/io/security_context.dart
@@ -14,14 +14,6 @@
  *
  * Certificates and keys can be added to a SecurityContext from either PEM
  * or PKCS12 containers.
- *
- * [usePrivateKey], [setTrustedCertificates], [useCertificateChain], and
- * [setClientAuthorities] are deprecated. They have been renamed
- * [usePrivateKeySync], [setTrustedCertificatesSync], [useCertificateChainSync],
- * and [setClientAuthoritiesSync] to reflect the fact that they do blocking
- * IO. Async-friendly versions have been added in [usePrivateKeyBytes],
- * [setTrustedCertificatesBytes], [useCertificateChainBytes], and
- * [setClientAuthoritiesBytes].
  */
 abstract class SecurityContext {
   external factory SecurityContext();
@@ -42,23 +34,21 @@
    *
    * A secure connection using this SecurityContext will use this key with
    * the server or client certificate to sign and decrypt messages.
-   * [keyFile] is the path to a PEM or PKCS12 file containing an encrypted
-   * private key, encrypted with [password].  An unencrypted file can be
-   * used, but this is not usual.
+   * [file] is the path to a PEM or PKCS12 file containing an encrypted
+   * private key, encrypted with [password]. Assuming it is well-formatted, all
+   * other contents of [file] are ignored. An unencrypted file can be used,
+   * but this is not usual.
+   *
+   * NB: This function calls [ReadFileAsBytesSync], and will block on file IO.
+   * Prefer using [usePrivateKeyBytes].
    */
-  void usePrivateKeySync(String keyFile, {String password});
-
-  /**
-   * [usePrivateKey] is deprecated. Use [usePrivateKeySync] or
-   * [usePrivateKeyBytes].
-   */
-  @deprecated
-  void usePrivateKey(String keyFile, {String password});
+  void usePrivateKey(String file, {String password});
 
   /**
    * Sets the private key for a server certificate or client certificate.
    *
-   * Like [usePrivateKeyBytesSync], but takes the contents of the file.
+   * Like [usePrivateKey], but takes the contents of the file as a list
+   * of bytes.
    */
   void usePrivateKeyBytes(List<int> keyBytes, {String password});
 
@@ -69,24 +59,21 @@
    * [file] is the path to a PEM or PKCS12 file containing X509 certificates,
    * usually root certificates from certificate authorities. For PKCS12 files,
    * [password] is the password for the file. For PEM files, [password] is
+   * ignored. Assuming it is well-formatted, all other contents of [file] are
    * ignored.
+   *
+   * NB: This function calls [ReadFileAsBytesSync], and will block on file IO.
+   * Prefer using [setTrustedCertificatesBytes].
    */
-  void setTrustedCertificatesSync(String file, {String password});
-
-  /**
-   * [setTrustedCertificates] is deprecated. Use [setTrustedCertificatesSync]
-   * or [setTrustedCertificatesBytes].
-   */
-  @deprecated
   void setTrustedCertificates(String file, {String password});
 
   /**
    * Sets the set of trusted X509 certificates used by [SecureSocket]
    * client connections, when connecting to a secure server.
    *
-   * Like [setTrustedCertificatesSync] but takes the contents of the file.
+   * Like [setTrustedCertificates] but takes the contents of the file.
    */
-  void setTrustedCertificatesBytes(List<int> certBytes,{String password});
+  void setTrustedCertificatesBytes(List<int> certBytes, {String password});
 
   /**
    * Sets the chain of X509 certificates served by [SecureServer]
@@ -97,22 +84,19 @@
    * chain to the server certificate, and ending with the server certificate.
    * The private key for the server certificate is set by [usePrivateKey]. For
    * PKCS12 files, [password] is the password for the file. For PEM files,
-   * [password] is ignored.
+   * [password] is ignored. Assuming it is well-formatted, all
+   * other contents of [file] are ignored.
+   *
+   * NB: This function calls [ReadFileAsBytesSync], and will block on file IO.
+   * Prefer using [useCertificateChainBytes].
    */
-  void useCertificateChainSync(String file, {String password});
-
-  /**
-   * [useCertificateChain] is deprecated. Use [useCertificateChainSync]
-   * or [useCertificateChainBytes].
-   */
-  @deprecated
-  void useCertificateChain({String file, String directory, String password});
+  void useCertificateChain(String file, {String password});
 
   /**
    * Sets the chain of X509 certificates served by [SecureServer]
    * when making secure connections, including the server certificate.
    *
-   * Like [useCertificateChainSync] but takes the contents of the file.
+   * Like [useCertificateChain] but takes the contents of the file.
    */
   void useCertificateChainBytes(List<int> chainBytes, {String password});
 
@@ -124,15 +108,12 @@
    * [file] is a PEM or PKCS12 file containing the accepted signing
    * authority certificates - the authority names are extracted from the
    * certificates. For PKCS12 files, [password] is the password for the file.
-   * For PEM files, [password] is ignored.
+   * For PEM files, [password] is ignored. Assuming it is well-formatted, all
+   * other contents of [file] are ignored.
+   *
+   * NB: This function calls [ReadFileAsBytesSync], and will block on file IO.
+   * Prefer using [setClientAuthoritiesBytes].
    */
-  void setClientAuthoritiesSync(String file, {String password});
-
-  /**
-   * [setClientAuthorities] is deprecated. Use [setClientAuthoritiesSync]
-   * or [setClientAuthoritiesBytes].
-   */
-  @deprecated
   void setClientAuthorities(String file, {String password});
 
   /**
@@ -140,7 +121,7 @@
    * as accepted, when requesting a client certificate from a connecting
    * client.
    *
-   * Like [setClientAuthoritySync] but takes the contents of the file.
+   * Like [setClientAuthority] but takes the contents of the file.
    */
   void setClientAuthoritiesBytes(List<int> authCertBytes, {String password});
 
diff --git a/sdk/lib/rules.gni b/sdk/lib/rules.gni
index 93ade221..0aa80f8 100644
--- a/sdk/lib/rules.gni
+++ b/sdk/lib/rules.gni
@@ -9,10 +9,13 @@
 #       The name of a Dart SDK library.
 #
 # Optional arguments:
+#   destination
+#       Base path to copy sources. Default value is "$root_gen_dir/dart_sdk".
+#
 #   dart_root
 #       Path to the Dart SDK source root. Default value is "//dart".
 #
-# The sources will be copied into $root_gen_dir/dart_sdk_libs/$sdk_lib_name/.
+# The sources will be copied into $root_gen_dir/dart_sdk/$sdk_lib_name/.
 #
 template("dart_sdk_lib_copy") {
   assert(defined(invoker.sdk_lib_name))
@@ -21,6 +24,11 @@
   } else {
     dart_root = rebase_path("//dart")
   }
+  if (defined(invoker.destination)) {
+    destination = invoker.destination
+  } else {
+    destination = "$root_gen_dir/dart_sdk"
+  }
   dart_sdk_sdk_lib_path =
       rebase_path("sdk/lib", "", dart_root)
   dart_sdk_tools_gypi_to_gn_path =
@@ -39,6 +47,6 @@
                   [rebase_path(lib_sources_gypi, "", lib_path)])
   copy(target_name) {
     sources = rebase_path(sdk_lib_sources_gypi.sources, "", lib_path)
-    outputs = [ "$root_gen_dir/dart_sdk_libs/$lib_name/{{source_file_part}}" ]
+    outputs = [ "$destination/$lib_name/{{source_file_part}}" ]
   }
 }
diff --git a/tests/co19/co19-dartium.status b/tests/co19/co19-dartium.status
index e8e6c56..eb9b059 100644
--- a/tests/co19/co19-dartium.status
+++ b/tests/co19/co19-dartium.status
@@ -18,6 +18,31 @@
 [ $compiler == none && $runtime == dartium && $system != windows ]
 LayoutTests/fast/css/font-face-unicode-range-monospace_t01: RuntimeError # co19-roll r761: Please triage this failure.
 
+[ $compiler == none && $runtime == dartium && ($system == windows || $system == linux) ]
+LayoutTests/fast/canvas/webgl/buffer-data-array-buffer_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/canvas-zero-size_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/compressed-tex-image_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/context-lost_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/draw-arrays-out-of-bounds_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/draw-elements-out-of-bounds_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/gl-enum-tests_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/gl-object-get-calls_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/gl-uniformmatrix4fv_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/gl-vertex-attrib-zero-issues_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/gl-vertex-attrib_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/index-validation-copies-indices_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/index-validation-crash-with-buffer-sub-data_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/index-validation-verifies-too-many-indices_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/index-validation-with-resized-buffer_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/index-validation_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/invalid-passed-params_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/null-uniform-location_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/program-test_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/tex-image-and-uniform-binding-bugs_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/tex-input-validation_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/texImageTest_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/texture-transparent-pixels-initialized_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+
 [ $compiler == none && $runtime == dartium && $mode == debug ]
 WebPlatformTest/html/semantics/embedded-content/media-elements/interfaces/TextTrack/mode_t01: Skip # Issue 19495.
 WebPlatformTest/html/semantics/forms/the-datalist-element/datalistoptions_t01: Skip # Issue 20540.
@@ -197,7 +222,6 @@
 LayoutTests/fast/canvas/canvas-getImageData-invalid_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/canvas/canvas-large-dimensions_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/canvas/canvas-large-fills_t01: RuntimeError # co19-roll r761: Please triage this failure.
-LayoutTests/fast/canvas/canvas-lineDash-input-sequence_t01: RuntimeError # Dartium 45 roll. Issue 25754
 LayoutTests/fast/canvas/canvas-lose-restore-googol-size_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/canvas/canvas-lose-restore-max-int-size_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/canvas/draw-custom-focus-ring_t01: RuntimeError # co19-roll r761: Please triage this failure.
@@ -208,24 +232,18 @@
 LayoutTests/fast/canvas/webgl/attrib-location-length-limits_t01: Pass, RuntimeError # Issue 22026
 LayoutTests/fast/canvas/webgl/bad-arguments-test_t01: Pass, RuntimeError # Issue 20, 22026
 LayoutTests/fast/canvas/webgl/buffer-bind-test_t01: Pass, RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/buffer-data-array-buffer_t01: RuntimeError # Issue 22026
 LayoutTests/fast/canvas/webgl/canvas-2d-webgl-texture_t01: RuntimeError # Issue 25653
 LayoutTests/fast/canvas/webgl/canvas-resize-crash_t01: Skip # Causes following tests to fail. co19-roll r761: Please triage this failure.
 LayoutTests/fast/canvas/webgl/canvas-test_t01: Pass, RuntimeError # co19-roll r801: Please triage this failure.
 LayoutTests/fast/canvas/webgl/canvas-test_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/canvas-zero-size_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/compressed-tex-image_t01: RuntimeError # Issue 22026
 LayoutTests/fast/canvas/webgl/context-attributes-alpha-depth-stencil-antialias-t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/context-attributes-alpha-depth-stencil-antialias-t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/canvas/webgl/context-destroyed-crash_t01: Pass, RuntimeError # Issue 22026
 LayoutTests/fast/canvas/webgl/context-lost-restored_t01: RuntimeError # Issue 25653
-LayoutTests/fast/canvas/webgl/context-lost_t01: RuntimeError # Issue 20, 22026
 LayoutTests/fast/canvas/webgl/copy-tex-image-and-sub-image-2d_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/copy-tex-image-and-sub-image-2d_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/canvas/webgl/css-webkit-canvas-repaint_t01: Pass, RuntimeError # Issue 22026
 LayoutTests/fast/canvas/webgl/css-webkit-canvas_t01: Pass, RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/draw-arrays-out-of-bounds_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/draw-elements-out-of-bounds_t01: RuntimeError # Issue 22026
 LayoutTests/fast/canvas/webgl/draw-webgl-to-canvas-2d_t01: Pass, RuntimeError # Issue 22026
 LayoutTests/fast/canvas/webgl/drawingbuffer-test_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/canvas/webgl/error-reporting_t01: Pass, RuntimeError # Issue 22026
@@ -239,31 +257,18 @@
 LayoutTests/fast/canvas/webgl/get-active-test_t01: Pass, RuntimeError # Issue 22026
 LayoutTests/fast/canvas/webgl/gl-bind-attrib-location-test_t01: RuntimeError # Issue 25653
 LayoutTests/fast/canvas/webgl/gl-enable-enum-test_t01: Pass, RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/gl-enum-tests_t01: RuntimeError # Issue 22026
 LayoutTests/fast/canvas/webgl/gl-get-calls_t01: Pass, RuntimeError # Issue 22026
 LayoutTests/fast/canvas/webgl/gl-getshadersource_t01: Pass, RuntimeError # Issue 22026
 LayoutTests/fast/canvas/webgl/gl-getstring_t01: Pass, RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/gl-object-get-calls_t01: RuntimeError #  Pass, Issue 20, 22026
 LayoutTests/fast/canvas/webgl/gl-pixelstorei_t01: RuntimeError # Issue 25653
 LayoutTests/fast/canvas/webgl/gl-teximage_t01: RuntimeError # Issue 22026
 LayoutTests/fast/canvas/webgl/gl-teximage_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/gl-uniformmatrix4fv_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/gl-vertex-attrib-zero-issues_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/gl-vertex-attrib_t01: RuntimeError # Issue 22026
 LayoutTests/fast/canvas/webgl/gl-vertexattribpointer_t01: Pass, RuntimeError # Issue 22026
 LayoutTests/fast/canvas/webgl/glsl-conformance_t01: Pass, RuntimeError # Issue 22026
 LayoutTests/fast/canvas/webgl/incorrect-context-object-behaviour_t01: Pass, RuntimeError # Issue 20, 22026
-LayoutTests/fast/canvas/webgl/index-validation-copies-indices_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/index-validation-crash-with-buffer-sub-data_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/index-validation-verifies-too-many-indices_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/index-validation-with-resized-buffer_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/index-validation_t01: RuntimeError # Issue 22026
 LayoutTests/fast/canvas/webgl/invalid-UTF-16_t01: Pass, RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/invalid-passed-params_t01: RuntimeError # Issue 20, 22026
-LayoutTests/fast/canvas/webgl/invalid-passed-params_t01: RuntimeError # Issue 22026
 LayoutTests/fast/canvas/webgl/is-object_t01: RuntimeError, Pass # co19-roll r761: Please triage this failure.
 LayoutTests/fast/canvas/webgl/null-object-behaviour_t01: Pass, RuntimeError # Issue 20, 22026
-LayoutTests/fast/canvas/webgl/null-uniform-location_t01: RuntimeError # Issue 22026
 LayoutTests/fast/canvas/webgl/object-deletion-behaviour_t01: RuntimeError # Issue 22026
 LayoutTests/fast/canvas/webgl/object-deletion-behaviour_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/oes-element-index-uint_t01: Pass, RuntimeError # co19-roll r801: Please triage this failure.
@@ -271,7 +276,6 @@
 LayoutTests/fast/canvas/webgl/oes-vertex-array-object_t01: RuntimeError # Issue 25653
 LayoutTests/fast/canvas/webgl/point-size_t01: RuntimeError # Issue 25653
 LayoutTests/fast/canvas/webgl/premultiplyalpha-test_t01: RuntimeError # co19-roll r761: Please triage this failure.
-LayoutTests/fast/canvas/webgl/program-test_t01: RuntimeError # Issue 22026
 LayoutTests/fast/canvas/webgl/read-pixels-pack-alignment_t01: RuntimeError # Issue 25653
 LayoutTests/fast/canvas/webgl/read-pixels-test_t01: RuntimeError # Issue 25653
 LayoutTests/fast/canvas/webgl/renderbuffer-initialization_t01: RuntimeError, Pass # co19-roll r761: Please triage this failure.
@@ -311,23 +315,18 @@
 LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-video-rgba5551_t01: Skip # Issue 20540
 LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-video_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-video_t01: Skip # Issue 20540
-LayoutTests/fast/canvas/webgl/tex-image-and-uniform-binding-bugs_t01: RuntimeError # Issue 22026
 LayoutTests/fast/canvas/webgl/tex-image-webgl_t01: RuntimeError # Issue 25653
-LayoutTests/fast/canvas/webgl/tex-input-validation_t01: RuntimeError # Issue 20, 22026
-LayoutTests/fast/canvas/webgl/tex-input-validation_t01: RuntimeError # Issue 22026
 LayoutTests/fast/canvas/webgl/tex-sub-image-2d-bad-args_t01: Pass, RuntimeError # Issue 20, 22026
 LayoutTests/fast/canvas/webgl/tex-sub-image-2d_t01: RuntimeError # Issue 22026
 LayoutTests/fast/canvas/webgl/tex-sub-image-2d_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/tex-sub-image-cube-maps_t01: RuntimeError # Issue 22026
 LayoutTests/fast/canvas/webgl/tex-sub-image-cube-maps_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/texImage2DImageDataTest_t01: RuntimeError # Issue 25653
-LayoutTests/fast/canvas/webgl/texImageTest_t01: RuntimeError # Issue 22026
 LayoutTests/fast/canvas/webgl/texture-active-bind_t01: RuntimeError # Issue 25653
 LayoutTests/fast/canvas/webgl/texture-bindings-uneffected-on-resize_t01: RuntimeError # Issue 25653
 LayoutTests/fast/canvas/webgl/texture-color-profile_t01: RuntimeError # Issue 25653
 LayoutTests/fast/canvas/webgl/texture-complete_t01: RuntimeError # Issue 25653
 LayoutTests/fast/canvas/webgl/texture-npot_t01: RuntimeError # Issue 25653
-LayoutTests/fast/canvas/webgl/texture-transparent-pixels-initialized_t01: RuntimeError # Issue 22026
 LayoutTests/fast/canvas/webgl/triangle_t01: RuntimeError, Pass # co19-roll r761: Please triage this failure.
 LayoutTests/fast/canvas/webgl/uniform-location-length-limits_t01: Pass, RuntimeError # Issue 22026
 LayoutTests/fast/canvas/webgl/uniform-location_t01: RuntimeError # Please triage this failure
@@ -629,8 +628,6 @@
 LayoutTests/fast/files/blob-close-read_t01: RuntimeError # co19-roll r786: Please triage this failure.
 LayoutTests/fast/files/blob-close-revoke_t01: RuntimeError # Experimental feature not exposed anywhere yet
 LayoutTests/fast/files/blob-close_t01: RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/files/blob-constructor_t01: RuntimeError # Dartium 45 roll. Issue 25754
-LayoutTests/fast/files/file-reader-fffd_t01: RuntimeError # Dartium 45 roll. Issue 25754
 LayoutTests/fast/files/xhr-response-blob_t01: RuntimeError # co19-roll r786: Please triage this failure.
 LayoutTests/fast/filesystem/async-operations_t01: Pass, RuntimeError # co19-roll r786: Please triage this failure.
 LayoutTests/fast/filesystem/directory-entry-to-uri_t01: RuntimeError # co19-roll r786: Please triage this failure.
diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status
index 01a850a..0fc268d 100644
--- a/tests/co19/co19-runtime.status
+++ b/tests/co19/co19-runtime.status
@@ -143,7 +143,8 @@
 Language/Errors_and_Warnings/static_warning_t05: RuntimeError # Please triage this failure
 Language/Errors_and_Warnings/static_warning_t06: RuntimeError # Please triage this failure
 
-[ ($noopt || $compiler == precompiler) ]
+[ $noopt || $compiler == precompiler ]
+Language/Metadata/*: SkipByDesign # Uses dart:mirrors
 LibTest/collection/ListBase/ListBase_class_A01_t02: Pass, Timeout
 LibTest/collection/ListMixin/ListMixin_class_A01_t02: Pass, Timeout
 LibTest/core/Map/Map_class_A01_t04: Pass, Timeout
@@ -152,13 +153,15 @@
 Language/Mixins/Mixin_Application/error_t02: Pass
 Language/Mixins/declaring_constructor_t01: Pass
 Language/Expressions/Property_Extraction/Named_Constructor_Extraction/deferred_type_t01: Pass
-Language/Metadata/*: Skip # Uses dart:mirrors
 
 [ $runtime == dart_precompiled ]
 LibTest/isolate/Isolate/spawnUri*: RuntimeError # Isolate.spawnUri
+Language/Expressions/Constants/identifier_denotes_a_constant_t05: Crash # Issue 25892
+Language/Expressions/Constants/static_method_t01: Crash # Issue 25892
 
 [ $runtime == dart_product ]
 LibTest/isolate/Isolate/spawnUri*: Skip # Isolate.spawnUri
+Language/Metadata/*: SkipByDesign # Uses dart:mirrors
 
 [ $runtime == vm && $mode == product ]
 LibTest/typed_data/Float32List/runtimeType_A01_t01: Fail,OK  # Expects exact type name.
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
index 3d4c849..52a0522 100644
--- a/tests/corelib/corelib.status
+++ b/tests/corelib/corelib.status
@@ -154,19 +154,19 @@
 [ $system == windows && $arch == x64 ]
 stopwatch_test: Skip  # Flaky test due to expected performance behaviour.
 
-[ $runtime != d8 && $runtime != vm ]
+[ $runtime != d8 && $runtime != vm && $runtime != dart_precompiled ]
 # The regexp tests are not verified to work on non d8/vm platforms yet.
 regexp/*: Skip
 
 [ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) ]
 regexp/global_test: Skip # Timeout. Issue 21709 and 21708
 
-[ $runtime != vm && $compiler != dart2analyzer]
+[ $runtime != vm && $runtime != dart_precompiled && $compiler != dart2analyzer]
 data_resource_test: RuntimeError # Issue 23825 (not implemented yet).
 file_resource_test: Skip, OK # VM specific test, uses dart:io.
 http_resource_test: Skip, OK # VM specific test, uses dart:io.
 
-[ $runtime != vm && $compiler != dart2analyzer && $cps_ir == false ]
+[ $runtime != vm && $runtime != dart_precompiled && $compiler != dart2analyzer && $cps_ir == false ]
 package_resource_test: RuntimeError # Issue 23825 (not implemented yet).
 
 [ $mode == debug ]
@@ -184,13 +184,19 @@
 [ $compiler == dart2js && $cps_ir && $host_checked ]
 regexp/pcre_test: Crash # Stack Overflow
 
-[ ($noopt || $compiler == precompiler) ]
+[ $noopt || $compiler == precompiler ]
+# Stacktraces in precompilation omit inlined frames.
+stacktrace_current_test: Pass, RuntimeError
+error_stack_trace1_test: Pass, RuntimeError
+
+[ $noopt || $compiler == precompiler ]
 apply3_test: CompileTimeError # Imports dart:mirrors
 regexp/stack-overflow_test: RuntimeError, OK # Smaller limit with irregex interpreter
 big_integer_huge_mul_vm_test: Pass, Timeout # --no_intrinsify
 big_integer_parsed_mul_div_vm_test: Pass, Timeout # --no_intrinsify
 int_parse_radix_test: Pass, Timeout # --no_intrinsify
 
-[ ($runtime == dart_product) ]
+[ $runtime == dart_product ]
 data_resource_test: Skip # Resolve URI not supported yet in product mode.
 package_resource_test: Skip # Resolve URI not supported yet in product mode.
+apply3_test: SkipByDesign # Imports dart:mirrors
diff --git a/tests/html/html.status b/tests/html/html.status
index cf55429..1facc17 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -18,10 +18,6 @@
 native_gc_test: Skip # Dartium JSInterop failure
 transferables_test: RuntimeError # Dartium JSInterop failure
 
-blob_constructor_test: RuntimeError # Dartium 45 roll. Issue 25754
-crypto_test/functional: RuntimeError # Dartium 45 roll. Issue 25754
-url_test: RuntimeError # Dartium 45 roll. Issue 25754
-
 [ $compiler == none && ($runtime == drt || $runtime == dartium ) ]
 worker_api_test: Fail # Issue 10223
 resource_http_test: Fail # Issue 24203
diff --git a/tests/isolate/isolate.status b/tests/isolate/isolate.status
index 4149d7d..953be4d 100644
--- a/tests/isolate/isolate.status
+++ b/tests/isolate/isolate.status
@@ -139,27 +139,31 @@
 spawn_uri_fail_test: SkipByDesign  # Uses dart:io.
 scenarios/*: SkipByDesign  # Use automatic package resolution, spawnFunction and .dart URIs.
 
-[ ($noopt || $compiler == precompiler) ]
+[ $noopt || $compiler == precompiler || $runtime == dart_product ]
 # Imports dart:mirrors
-count_test: CompileTimeError
-cross_isolate_message_test: CompileTimeError
-illegal_msg_function_test: CompileTimeError
-illegal_msg_mirror_test: CompileTimeError
-isolate_complex_messages_test: CompileTimeError
-mandel_isolate_test: CompileTimeError
-message2_test: CompileTimeError
-message_test: CompileTimeError
-mint_maker_test: CompileTimeError
-nested_spawn2_test: CompileTimeError
-nested_spawn_test: CompileTimeError
-raw_port_test: CompileTimeError
-request_reply_test: CompileTimeError
-spawn_function_custom_class_test: CompileTimeError
-spawn_function_test: CompileTimeError
-stacktrace_message_test: CompileTimeError
-stacktrace_message_test: CompileTimeError
-static_function_test: CompileTimeError
-unresolved_ports_test: CompileTimeError
+count_test: SkipByDesign
+cross_isolate_message_test: SkipByDesign
+illegal_msg_function_test: SkipByDesign
+illegal_msg_mirror_test: SkipByDesign
+isolate_complex_messages_test: SkipByDesign
+mandel_isolate_test: SkipByDesign
+message2_test: SkipByDesign
+message_test: SkipByDesign
+mint_maker_test: SkipByDesign
+nested_spawn2_test: SkipByDesign
+nested_spawn_test: SkipByDesign
+raw_port_test: SkipByDesign
+request_reply_test: SkipByDesign
+spawn_function_custom_class_test: SkipByDesign
+spawn_function_test: SkipByDesign
+stacktrace_message_test: SkipByDesign
+stacktrace_message_test: SkipByDesign
+static_function_test: SkipByDesign
+unresolved_ports_test: SkipByDesign
+
+[ $compiler == precompiler ]
+function_send_test: RuntimeError # Issue 25892
+message3_test/fun: RuntimeError # Issue 25892
 
 [ $runtime == dart_precompiled || $runtime == dart_product ]
 deferred_in_isolate_test: Skip # Isolate.spawnUri
diff --git a/tests/language/language.status b/tests/language/language.status
index b2409a5..42bb58b 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -45,8 +45,6 @@
 async_star_cancel_while_paused_test: RuntimeError
 async_star_await_pauses_test: Skip # Times out. Issue 23996
 
-library_env_test: RuntimeError
-
 accessor_conflict_export2_test: RuntimeError # Issue 25625
 accessor_conflict_import2_test: RuntimeError # Issue 25625
 accessor_conflict_import_prefixed2_test: RuntimeError # Issue 25625
@@ -106,6 +104,9 @@
 stack_overflow_stacktrace_test: Skip # Crashes. Issue 17440.
 large_class_declaration_test: SkipSlow # Times out. Issue 20352
 
+[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) && $arch == arm64 ]
+large_class_declaration_test: SkipSlow # Uses too much memory.
+
 [ $compiler == none && ($runtime == dartium || $runtime == drt) && $mode == debug ]
 large_class_declaration_test: SkipSlow # Times out. Issue 20352
 
@@ -118,31 +119,38 @@
 [ ($compiler == none || $compiler == precompiler || $compiler == dart2app) && (($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) || $runtime == drt || $runtime == dartium) && $arch == ia32 ]
 vm/regress_24517_test: Pass, Fail # Issue 24517.
 
-[ ($noopt || $compiler == precompiler) ]
-# Imports dart:mirrors
-const_evaluation_test: CompileTimeError
-deferred_constraints_constants_test/none: CompileTimeError
-deferred_constraints_constants_test/reference_after_load: CompileTimeError
-enum_mirror_test: CompileTimeError
-field_increment_bailout_test: CompileTimeError
-instance_creation_in_function_annotation_test: CompileTimeError
-invocation_mirror2_test: CompileTimeError
-invocation_mirror_invoke_on2_test: CompileTimeError
-invocation_mirror_invoke_on_test: CompileTimeError
-issue21079_test: CompileTimeError
-many_overridden_no_such_method_test: CompileTimeError
-no_such_method_test: CompileTimeError
-null_test/none: CompileTimeError
-overridden_no_such_method_test: CompileTimeError
-redirecting_factory_reflection_test: CompileTimeError
-regress_13462_0_test: CompileTimeError
-regress_13462_1_test: CompileTimeError
-regress_18535_test: CompileTimeError
-super_call4_test: CompileTimeError
-super_getter_setter_test: CompileTimeError
-vm/reflect_core_vm_test: CompileTimeError
+[ $noopt || $compiler == precompiler ]
+# Stacktraces in precompilation omit inlined frames.
+full_stacktrace1_test: Pass, RuntimeError
+full_stacktrace2_test: Pass, RuntimeError
+full_stacktrace3_test: Pass, RuntimeError
+stack_trace_test: Pass, RuntimeError
+stacktrace_rethrow_error_test: Pass, RuntimeError
+stacktrace_rethrow_nonerror_test: Pass, RuntimeError
+stacktrace_test: Pass, RuntimeError
 
-deferred_global_test: RuntimeError # Issue 25845
+[ $noopt || $compiler == precompiler || $runtime == dart_product ]
+# Imports dart:mirrors
+const_evaluation_test: SkipByDesign
+deferred_constraints_constants_test: SkipByDesign
+enum_mirror_test: SkipByDesign
+field_increment_bailout_test: SkipByDesign
+instance_creation_in_function_annotation_test: SkipByDesign
+invocation_mirror2_test: SkipByDesign
+invocation_mirror_invoke_on2_test: SkipByDesign
+invocation_mirror_invoke_on_test: SkipByDesign
+issue21079_test: SkipByDesign
+many_overridden_no_such_method_test: SkipByDesign
+no_such_method_test: SkipByDesign
+null_test/none: SkipByDesign
+overridden_no_such_method_test: SkipByDesign
+redirecting_factory_reflection_test: SkipByDesign
+regress_13462_0_test: SkipByDesign
+regress_13462_1_test: SkipByDesign
+regress_18535_test: SkipByDesign
+super_call4_test: SkipByDesign
+super_getter_setter_test: SkipByDesign
+vm/reflect_core_vm_test: SkipByDesign
 
 [ ($noopt || $compiler == precompiler || $compiler == dart2app) ]
 # Deferred loading happens eagerly
@@ -150,6 +158,7 @@
 deferred_inheritance_constraints_test: Skip
 deferred_load_constants_test: Skip # multitest gets confused
 tearoff_basic_test: RuntimeError, Crash # Conflicting flag.
+deferred_global_test: RuntimeError # Issue 25845
 
 vm/type_vm_test: RuntimeError # Expects line and column numbers
 vm/type_cast_vm_test: RuntimeError # Line number mismatch.
@@ -171,3 +180,21 @@
 
 [ $runtime == vm && $mode == product ]
 vm/type_vm_test: Fail,OK  # Expects exact type name.
+
+[ ($compiler == none || $compiler == precompiler || $compiler == dart2app) && $browser ]
+# The following tests are supposed to fail.
+library_env_test/has_io_support: RuntimeError, OK
+library_env_test/has_no_html_support: RuntimeError, OK
+
+[ ($compiler == none || $compiler == precompiler || $compiler == dart2app) && $browser != true ]
+# The following tests are supposed to fail.
+library_env_test/has_html_support: RuntimeError, OK
+library_env_test/has_no_io_support: RuntimeError, OK
+
+[ $compiler == none && $noopt == false && $mode != product ]
+# The following tests are supposed to fail.
+library_env_test/has_no_mirror_support: RuntimeError, OK
+
+[ $noopt || $compiler == precompiler || $mode == product ]
+# The following tests are supposed to fail.
+library_env_test/has_mirror_support: RuntimeError, OK
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 90527a4..a3327e4 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -25,7 +25,7 @@
 mixin_of_mixin_test: CompileTimeError # Issue 23773
 
 # The following tests are supposed to fail.
-# When run for testing dart2js supports all dart:X libraries (because it
+# In testing-mode, dart2js supports all dart:X libraries (because it
 # uses '--categories=all').
 library_env_test/has_no_html_support: RuntimeError, OK
 library_env_test/has_no_io_support: RuntimeError, OK
diff --git a/tests/language/library_env_test.dart b/tests/language/library_env_test.dart
index 7095d83..bbe3b84 100644
--- a/tests/language/library_env_test.dart
+++ b/tests/language/library_env_test.dart
@@ -5,7 +5,7 @@
 import 'package:expect/expect.dart';
 
 main() {
-  const NOT_PRESENT = null;
+  const NOT_PRESENT = false;
 
   Expect.isTrue(const bool.fromEnvironment("dart.library.async"));
   Expect.isTrue(const bool.fromEnvironment("dart.library.collection"));
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index 4a43727..a8623b4 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -233,7 +233,7 @@
 mirrors/native_class_test: Fail, OK # This test is meant to run in a browser.
 mirrors/deferred_type_test: CompileTimeError, OK # Don't have a multitest marker for dynamic compile time errors.
 
-[ ($compiler == none || $compiler == precompiler || $compiler == dart2app) ]
+[ $compiler == none || $compiler == precompiler || $compiler == dart2app ]
 async/timer_not_available_test: SkipByDesign # only meant to test when there is no way to implement timer (currently only in d8)
 
 mirrors/symbol_validation_test: RuntimeError # Issue 13596
@@ -348,7 +348,7 @@
 [ $noopt && $arch == simarm64 ]
 async/slow_consumer2_test: Pass, RuntimeError # Issue 25726
 
-[ ($noopt || $compiler == precompiler) ]
+[ $noopt || $compiler == precompiler ]
 mirrors/*: SkipByDesign
 convert/chunked_conversion_utf88_test: Pass, Timeout
 convert/utf85_test: Pass, Timeout
diff --git a/tests/standalone/io/http_proxy_advanced_test.dart b/tests/standalone/io/http_proxy_advanced_test.dart
index 81a43c9..1d2e585 100644
--- a/tests/standalone/io/http_proxy_advanced_test.dart
+++ b/tests/standalone/io/http_proxy_advanced_test.dart
@@ -12,12 +12,12 @@
 String localFile(path) => Platform.script.resolve(path).toFilePath();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
-  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
-                      password: 'dartdart');
+  ..useCertificateChain(localFile('certificates/server_chain.pem'))
+  ..usePrivateKey(localFile('certificates/server_key.pem'),
+                  password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
 
 class Server {
   HttpServer server;
diff --git a/tests/standalone/io/http_proxy_test.dart b/tests/standalone/io/http_proxy_test.dart
index 042807c..e2505f3 100644
--- a/tests/standalone/io/http_proxy_test.dart
+++ b/tests/standalone/io/http_proxy_test.dart
@@ -12,13 +12,12 @@
 String localFile(path) => Platform.script.resolve(path).toFilePath();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
-  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
-                      password: 'dartdart');
+  ..useCertificateChain(localFile('certificates/server_chain.pem'))
+  ..usePrivateKey(localFile('certificates/server_key.pem'),
+                  password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificatesSync(
-      localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
 
 class Server {
   HttpServer server;
diff --git a/tests/standalone/io/https_bad_certificate_test.dart b/tests/standalone/io/https_bad_certificate_test.dart
index d90acd4..90c630f 100644
--- a/tests/standalone/io/https_bad_certificate_test.dart
+++ b/tests/standalone/io/https_bad_certificate_test.dart
@@ -14,9 +14,9 @@
 String localFile(path) => Platform.script.resolve(path).toFilePath();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
-  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
-                      password: 'dartdart');
+  ..useCertificateChain(localFile('certificates/server_chain.pem'))
+  ..usePrivateKey(localFile('certificates/server_key.pem'),
+                  password: 'dartdart');
 
 class CustomException {}
 
@@ -31,7 +31,7 @@
   });
 
   SecurityContext goodContext = new SecurityContext()
-    ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+    ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
   SecurityContext badContext = new SecurityContext();
   SecurityContext defaultContext = SecurityContext.defaultContext;
 
diff --git a/tests/standalone/io/https_client_certificate_test.dart b/tests/standalone/io/https_client_certificate_test.dart
index 27b97ed..dc11a45 100644
--- a/tests/standalone/io/https_client_certificate_test.dart
+++ b/tests/standalone/io/https_client_certificate_test.dart
@@ -13,17 +13,17 @@
 String localFile(path) => Platform.script.resolve(path).toFilePath();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
-  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
-                      password: 'dartdart');
+  ..useCertificateChain(localFile('certificates/server_chain.pem'))
+  ..usePrivateKey(localFile('certificates/server_key.pem'),
+                  password: 'dartdart');
 // TODO: Specify which client certificate roots to trust.
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'))
+  ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'))
 // TODO: Set a client certificate here.
-  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
-  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
-                      password: 'dartdart');
+  ..useCertificateChain(localFile('certificates/server_chain.pem'))
+  ..usePrivateKey(localFile('certificates/server_key.pem'),
+                  password: 'dartdart');
 
 void main() {
   asyncStart();
diff --git a/tests/standalone/io/https_server_test.dart b/tests/standalone/io/https_server_test.dart
index c0bce81..3f9bc52 100644
--- a/tests/standalone/io/https_server_test.dart
+++ b/tests/standalone/io/https_server_test.dart
@@ -13,12 +13,12 @@
 String localFile(path) => Platform.script.resolve(path).toFilePath();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
-  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
-                      password: 'dartdart');
+  ..useCertificateChain(localFile('certificates/server_chain.pem'))
+  ..usePrivateKey(localFile('certificates/server_key.pem'),
+                  password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
 
 void testListenOn() {
   void test(void onDone()) {
diff --git a/tests/standalone/io/https_unauthorized_test.dart b/tests/standalone/io/https_unauthorized_test.dart
index cfa54c2..a556626 100644
--- a/tests/standalone/io/https_unauthorized_test.dart
+++ b/tests/standalone/io/https_unauthorized_test.dart
@@ -16,13 +16,12 @@
 String localFile(path) => Platform.script.resolve(path).toFilePath();
 
 SecurityContext untrustedServerContext = new SecurityContext()
-  ..useCertificateChainSync(localFile(
-      'certificates/untrusted_server_chain.pem'))
-  ..usePrivateKeySync(localFile('certificates/untrusted_server_key.pem'),
-                      password: 'dartdart');
+  ..useCertificateChain(localFile('certificates/untrusted_server_chain.pem'))
+  ..usePrivateKey(localFile('certificates/untrusted_server_key.pem'),
+                  password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
 
 Future<SecureServerSocket> runServer() {
   return HttpServer.bindSecure(
diff --git a/tests/standalone/io/raw_secure_server_closing_test.dart b/tests/standalone/io/raw_secure_server_closing_test.dart
index b63da9e..e6c084a 100644
--- a/tests/standalone/io/raw_secure_server_closing_test.dart
+++ b/tests/standalone/io/raw_secure_server_closing_test.dart
@@ -17,12 +17,12 @@
 String localFile(path) => Platform.script.resolve(path).toFilePath();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
-  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
-                      password: 'dartdart');
+  ..useCertificateChain(localFile('certificates/server_chain.pem'))
+  ..usePrivateKey(localFile('certificates/server_key.pem'),
+                  password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
 
 void testCloseOneEnd(String toClose) {
   asyncStart();
diff --git a/tests/standalone/io/raw_secure_server_socket_test.dart b/tests/standalone/io/raw_secure_server_socket_test.dart
index 0510ba6..ba34bed 100644
--- a/tests/standalone/io/raw_secure_server_socket_test.dart
+++ b/tests/standalone/io/raw_secure_server_socket_test.dart
@@ -17,12 +17,12 @@
 String localFile(path) => Platform.script.resolve(path).toFilePath();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
-  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
-                      password: 'dartdart');
+  ..useCertificateChain(localFile('certificates/server_chain.pem'))
+  ..usePrivateKey(localFile('certificates/server_key.pem'),
+                  password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
 
 void testSimpleBind() {
   asyncStart();
@@ -574,13 +574,13 @@
   var chain =
       Platform.script.resolve('certificates/untrusted_server_chain.pem')
       .toFilePath();
-  context.useCertificateChainSync(chain);
+  context.useCertificateChain(chain);
   testSimpleConnectFail(context, false);
   testSimpleConnectFail(context, true);
   var key =
       Platform.script.resolve('certificates/untrusted_server_key.pem')
        .toFilePath();
-  context.usePrivateKeySync(key, password: 'dartdart');
+  context.usePrivateKey(key, password: 'dartdart');
   testSimpleConnectFail(context, false);
   testSimpleConnectFail(context, true);
   testServerListenAfterConnect();
diff --git a/tests/standalone/io/raw_secure_socket_pause_test.dart b/tests/standalone/io/raw_secure_socket_pause_test.dart
index 9ca848e..0073cda 100644
--- a/tests/standalone/io/raw_secure_socket_pause_test.dart
+++ b/tests/standalone/io/raw_secure_socket_pause_test.dart
@@ -16,12 +16,12 @@
 String localFile(path) => Platform.script.resolve(path).toFilePath();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
-  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
-                      password: 'dartdart');
+  ..useCertificateChain(localFile('certificates/server_chain.pem'))
+  ..usePrivateKey(localFile('certificates/server_key.pem'),
+                  password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
 
 Future<HttpServer> startServer() {
   return HttpServer.bindSecure(
diff --git a/tests/standalone/io/raw_secure_socket_test.dart b/tests/standalone/io/raw_secure_socket_test.dart
index 04d8417..df3994e 100644
--- a/tests/standalone/io/raw_secure_socket_test.dart
+++ b/tests/standalone/io/raw_secure_socket_test.dart
@@ -16,12 +16,12 @@
 String localFile(path) => Platform.script.resolve(path).toFilePath();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
-  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
-                      password: 'dartdart');
+  ..useCertificateChain(localFile('certificates/server_chain.pem'))
+  ..usePrivateKey(localFile('certificates/server_key.pem'),
+                  password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
 
 main() async {
   List<int> message = "GET / HTTP/1.0\r\nHost: localhost\r\n\r\n".codeUnits;
diff --git a/tests/standalone/io/regress_21160_test.dart b/tests/standalone/io/regress_21160_test.dart
index 25d64e8..b3d39f1 100644
--- a/tests/standalone/io/regress_21160_test.dart
+++ b/tests/standalone/io/regress_21160_test.dart
@@ -13,12 +13,12 @@
 String localFile(path) => Platform.script.resolve(path).toFilePath();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
-  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
-                      password: 'dartdart');
+  ..useCertificateChain(localFile('certificates/server_chain.pem'))
+  ..usePrivateKey(localFile('certificates/server_key.pem'),
+                  password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
 
 // 10 KiB of i%256 data.
 Uint8List DATA = new Uint8List.fromList(
diff --git a/tests/standalone/io/secure_bad_certificate_test.dart b/tests/standalone/io/secure_bad_certificate_test.dart
index eeea66b..610bcdb 100644
--- a/tests/standalone/io/secure_bad_certificate_test.dart
+++ b/tests/standalone/io/secure_bad_certificate_test.dart
@@ -14,9 +14,9 @@
 String localFile(path) => Platform.script.resolve(path).toFilePath();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
-  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
-                      password: 'dartdart');
+  ..useCertificateChain(localFile('certificates/server_chain.pem'))
+  ..usePrivateKey(localFile('certificates/server_key.pem'),
+                  password: 'dartdart');
 
 class CustomException {}
 
@@ -30,7 +30,7 @@
     }, onError: (e) { if (e is! HandshakeException) throw e; });
 
   SecurityContext goodContext = new SecurityContext()
-    ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+    ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
   SecurityContext badContext = new SecurityContext();
   SecurityContext defaultContext = SecurityContext.defaultContext;
 
diff --git a/tests/standalone/io/secure_client_raw_server_test.dart b/tests/standalone/io/secure_client_raw_server_test.dart
index 00ea2dc..e8cb63d 100644
--- a/tests/standalone/io/secure_client_raw_server_test.dart
+++ b/tests/standalone/io/secure_client_raw_server_test.dart
@@ -16,12 +16,12 @@
 String localFile(path) => Platform.script.resolve(path).toFilePath();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
-  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
-                      password: 'dartdart');
+  ..useCertificateChain(localFile('certificates/server_chain.pem'))
+  ..usePrivateKey(localFile('certificates/server_key.pem'),
+                  password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
 
 InternetAddress HOST;
 Future<RawSecureServerSocket> startEchoServer() {
diff --git a/tests/standalone/io/secure_client_server_test.dart b/tests/standalone/io/secure_client_server_test.dart
index 360e9e4d..4d928ef 100644
--- a/tests/standalone/io/secure_client_server_test.dart
+++ b/tests/standalone/io/secure_client_server_test.dart
@@ -18,12 +18,12 @@
 String localFile(path) => Platform.script.resolve(path).toFilePath();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
-  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
-                      password: 'dartdart');
+  ..useCertificateChain(localFile('certificates/server_chain.pem'))
+  ..usePrivateKey(localFile('certificates/server_key.pem'),
+                  password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificatesSync(
+  ..setTrustedCertificates(
       localFile('certificates/trusted_certs.pem'));
 
 
diff --git a/tests/standalone/io/secure_multiple_client_server_test.dart b/tests/standalone/io/secure_multiple_client_server_test.dart
index 9515688..a0577df 100644
--- a/tests/standalone/io/secure_multiple_client_server_test.dart
+++ b/tests/standalone/io/secure_multiple_client_server_test.dart
@@ -19,12 +19,12 @@
 String localFile(path) => Platform.script.resolve(path).toFilePath();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
-  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
-                      password: 'dartdart');
+  ..useCertificateChain(localFile('certificates/server_chain.pem'))
+  ..usePrivateKey(localFile('certificates/server_key.pem'),
+                  password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
 
 Future startServer() {
   return SecureServerSocket.bind(HOST, 0, serverContext).then((server) {
diff --git a/tests/standalone/io/secure_server_client_certificate_test.dart b/tests/standalone/io/secure_server_client_certificate_test.dart
index e1cf015..6891037 100644
--- a/tests/standalone/io/secure_server_client_certificate_test.dart
+++ b/tests/standalone/io/secure_server_client_certificate_test.dart
@@ -14,27 +14,27 @@
 
 SecurityContext serverContext(String certType, String password) =>
   new SecurityContext()
-  ..useCertificateChainSync(
-      localFile('certificates/server_chain.$certType'), password: password)
-  ..usePrivateKeySync(
-      localFile('certificates/server_key.$certType'), password: password)
-  ..setTrustedCertificatesSync(localFile(
+  ..useCertificateChain(localFile(
+      'certificates/server_chain.$certType'), password: password)
+  ..usePrivateKey(localFile(
+      'certificates/server_key.$certType'), password: password)
+  ..setTrustedCertificates(localFile(
       'certificates/client_authority.$certType'), password: password)
-  ..setClientAuthoritiesSync(localFile(
+  ..setClientAuthorities(localFile(
       'certificates/client_authority.$certType'), password: password);
 
 SecurityContext clientCertContext(String certType, String password) =>
   new SecurityContext()
-  ..setTrustedCertificatesSync(
-      localFile('certificates/trusted_certs.$certType'), password: password)
-  ..useCertificateChainSync(
-      localFile('certificates/client1.$certType'), password: password)
-  ..usePrivateKeySync(
-      localFile('certificates/client1_key.$certType'), password: password);
+  ..setTrustedCertificates(localFile(
+      'certificates/trusted_certs.$certType'), password: password)
+  ..useCertificateChain(localFile(
+      'certificates/client1.$certType'), password: password)
+  ..usePrivateKey(localFile(
+      'certificates/client1_key.$certType'), password: password);
 
 SecurityContext clientNoCertContext(String certType, String password) =>
   new SecurityContext()
-  ..setTrustedCertificatesSync(localFile(
+  ..setTrustedCertificates(localFile(
       'certificates/trusted_certs.$certType'), password: password);
 
 Future testClientCertificate(
diff --git a/tests/standalone/io/secure_server_closing_test.dart b/tests/standalone/io/secure_server_closing_test.dart
index 1e2a2d7..159c6ae4 100644
--- a/tests/standalone/io/secure_server_closing_test.dart
+++ b/tests/standalone/io/secure_server_closing_test.dart
@@ -18,13 +18,12 @@
 String localFile(path) => Platform.script.resolve(path).toFilePath();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
-  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
-                      password: 'dartdart');
+  ..useCertificateChain(localFile('certificates/server_chain.pem'))
+  ..usePrivateKey(localFile('certificates/server_key.pem'),
+                  password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificatesSync(
-      localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
 
 void testCloseOneEnd(String toClose) {
   asyncStart();
diff --git a/tests/standalone/io/secure_server_socket_test.dart b/tests/standalone/io/secure_server_socket_test.dart
index 33cd57e..d3e2d1c 100644
--- a/tests/standalone/io/secure_server_socket_test.dart
+++ b/tests/standalone/io/secure_server_socket_test.dart
@@ -18,12 +18,12 @@
 String localFile(path) => Platform.script.resolve(path).toFilePath();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
-  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
-                      password: 'dartdart');
+  ..useCertificateChain(localFile('certificates/server_chain.pem'))
+  ..usePrivateKey(localFile('certificates/server_key.pem'),
+                  password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
 
 void testSimpleBind() {
   asyncStart();
diff --git a/tests/standalone/io/secure_session_resume_test.dart b/tests/standalone/io/secure_session_resume_test.dart
index c4738f6..15f2b0b 100644
--- a/tests/standalone/io/secure_session_resume_test.dart
+++ b/tests/standalone/io/secure_session_resume_test.dart
@@ -28,12 +28,12 @@
 String localFile(path) => Platform.script.resolve(path).toFilePath();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
-  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
-                      password: 'dartdart');
+  ..useCertificateChain(localFile('certificates/server_chain.pem'))
+  ..usePrivateKey(localFile('certificates/server_key.pem'),
+                  password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
 
 Future<SecureServerSocket> startServer() {
   return SecureServerSocket.bind(HOST,
diff --git a/tests/standalone/io/secure_socket_alpn_test.dart b/tests/standalone/io/secure_socket_alpn_test.dart
index 4b717b2..8599991 100644
--- a/tests/standalone/io/secure_socket_alpn_test.dart
+++ b/tests/standalone/io/secure_socket_alpn_test.dart
@@ -17,12 +17,12 @@
 String localFile(path) => Platform.script.resolve(path).toFilePath();
 
 SecurityContext clientContext() => new SecurityContext()
-  ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
 
 SecurityContext serverContext() => new SecurityContext()
-  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
-  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
-                      password: 'dartdart');
+  ..useCertificateChain(localFile('certificates/server_chain.pem'))
+  ..usePrivateKey(localFile('certificates/server_key.pem'),
+                  password: 'dartdart');
 
 // Tests that client/server with same protocol can securely establish a
 // connection, negotiate the protocol and can send data to each other.
diff --git a/tests/standalone/io/secure_socket_renegotiate_client.dart b/tests/standalone/io/secure_socket_renegotiate_client.dart
index 7886706..12f9245 100644
--- a/tests/standalone/io/secure_socket_renegotiate_client.dart
+++ b/tests/standalone/io/secure_socket_renegotiate_client.dart
@@ -15,7 +15,7 @@
 String localFile(path) => Platform.script.resolve(path).toFilePath();
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
 
 class ExpectException implements Exception {
   ExpectException(this.message);
diff --git a/tests/standalone/io/secure_socket_renegotiate_test.dart b/tests/standalone/io/secure_socket_renegotiate_test.dart
index 7cc9346..457cee6 100644
--- a/tests/standalone/io/secure_socket_renegotiate_test.dart
+++ b/tests/standalone/io/secure_socket_renegotiate_test.dart
@@ -17,9 +17,9 @@
 String localFile(path) => Platform.script.resolve(path).toFilePath();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
-  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
-                      password: 'dartdart');
+  ..useCertificateChain(localFile('certificates/server_chain.pem'))
+  ..usePrivateKey(localFile('certificates/server_key.pem'),
+                  password: 'dartdart');
 
 Future<SecureServerSocket> runServer() {
   return SecureServerSocket.bind(HOST_NAME, 0, serverContext)
diff --git a/tests/standalone/io/secure_socket_test.dart b/tests/standalone/io/secure_socket_test.dart
index c24fc5f..1566b5a 100644
--- a/tests/standalone/io/secure_socket_test.dart
+++ b/tests/standalone/io/secure_socket_test.dart
@@ -17,15 +17,15 @@
 
 SecurityContext serverContext(String certType, String password) =>
     new SecurityContext()
-    ..useCertificateChainSync(localFile('certificates/server_chain.$certType'),
-                              password: password)
-    ..usePrivateKeySync(localFile('certificates/server_key.$certType'),
-                        password: password);
+    ..useCertificateChain(localFile('certificates/server_chain.$certType'),
+                          password: password)
+    ..usePrivateKey(localFile('certificates/server_key.$certType'),
+                    password: password);
 
 SecurityContext clientContext(String certType, String password) =>
     new SecurityContext()
-    ..setTrustedCertificatesSync(localFile(
-        'certificates/trusted_certs.$certType'), password: password);
+    ..setTrustedCertificates(localFile('certificates/trusted_certs.$certType'),
+                             password: password);
 
 Future<HttpServer> startServer(String certType, String password) {
   return HttpServer.bindSecure(
diff --git a/tests/standalone/io/secure_unauthorized_client.dart b/tests/standalone/io/secure_unauthorized_client.dart
index 9c764a7..10392f2 100644
--- a/tests/standalone/io/secure_unauthorized_client.dart
+++ b/tests/standalone/io/secure_unauthorized_client.dart
@@ -11,7 +11,7 @@
 String localFile(path) => Platform.script.resolve(path).toFilePath();
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
 
 class ExpectException implements Exception {
   ExpectException(this.message);
diff --git a/tests/standalone/io/secure_unauthorized_test.dart b/tests/standalone/io/secure_unauthorized_test.dart
index 097a0d0..a600d74 100644
--- a/tests/standalone/io/secure_unauthorized_test.dart
+++ b/tests/standalone/io/secure_unauthorized_test.dart
@@ -14,10 +14,9 @@
 String localFile(path) => Platform.script.resolve(path).toFilePath();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainSync(localFile(
-      'certificates/untrusted_server_chain.pem'))
-  ..usePrivateKeySync(localFile('certificates/untrusted_server_key.pem'),
-                      password: 'dartdart');
+  ..useCertificateChain(localFile('certificates/untrusted_server_chain.pem'))
+  ..usePrivateKey(localFile('certificates/untrusted_server_key.pem'),
+                  password: 'dartdart');
 
 Future<SecureServerSocket> runServer() {
   return SecureServerSocket.bind(HOST_NAME, 0, serverContext)
diff --git a/tests/standalone/io/security_context_argument_test.dart b/tests/standalone/io/security_context_argument_test.dart
index 6d5e1e2..e5332ac 100644
--- a/tests/standalone/io/security_context_argument_test.dart
+++ b/tests/standalone/io/security_context_argument_test.dart
@@ -15,71 +15,71 @@
 
 void testUsePrivateKeyArguments() {
     var c = new SecurityContext();
-    c.useCertificateChainSync(localFile('certificates/server_chain.pem'));
+    c.useCertificateChain(localFile('certificates/server_chain.pem'));
 
     // Wrong password.
-    Expect.throws(() => c.usePrivateKeySync(
+    Expect.throws(() => c.usePrivateKey(
         localFile('certificates/server_key.pem')),
         tlsException);
-    Expect.throws(() => c.usePrivateKeySync(
-          localFile('certificates/server_key.pem'), password: "iHackSites"),
+    Expect.throws(() => c.usePrivateKey(
+        localFile('certificates/server_key.pem'), password: "iHackSites"),
         tlsException);
-    Expect.throws(() => c.usePrivateKeySync(
+    Expect.throws(() => c.usePrivateKey(
         localFile('certificates/server_key.p12')),
         tlsException);
-    Expect.throws(() => c.usePrivateKeySync(
-          localFile('certificates/server_key.p12'), password: "iHackSites"),
+    Expect.throws(() => c.usePrivateKey(
+        localFile('certificates/server_key.p12'), password: "iHackSites"),
         tlsException);
-    Expect.throws(() => c.setTrustedCertificatesSync(
+    Expect.throws(() => c.setTrustedCertificates(
         localFile('certificates/server_key.p12')),
         tlsException);
-    Expect.throws(() => c.setTrustedCertificatesSync(
-          localFile('certificates/server_key.p12'), password: "iHackSites"),
+    Expect.throws(() => c.setTrustedCertificates(
+        localFile('certificates/server_key.p12'), password: "iHackSites"),
         tlsException);
-    Expect.throws(() => c.useCertificateChainSync(
+    Expect.throws(() => c.useCertificateChain(
         localFile('certificates/server_key.p12')),
         tlsException);
-    Expect.throws(() => c.useCertificateChainSync(
-          localFile('certificates/server_key.p12'), password: "iHackSites"),
+    Expect.throws(() => c.useCertificateChain(
+        localFile('certificates/server_key.p12'), password: "iHackSites"),
         tlsException);
-    Expect.throws(() => c.setClientAuthoritiesSync(
+    Expect.throws(() => c.setClientAuthorities(
         localFile('certificates/server_key.p12')),
         argumentError);
-    Expect.throws(() => c.setClientAuthoritiesSync(
-          localFile('certificates/server_key.p12'), password: "iHackSites"),
+    Expect.throws(() => c.setClientAuthorities(
+        localFile('certificates/server_key.p12'), password: "iHackSites"),
         argumentError);
 
     // File does not exist
-    Expect.throws(() => c.usePrivateKeySync(
+    Expect.throws(() => c.usePrivateKey(
         localFile('certificates/server_key_oops.pem'),
                   password: "dartdart"),
         fileSystemException);
 
     // Wrong type for file name or data
-    Expect.throws(() => c.usePrivateKeySync(1), argumentOrTypeError);
-    Expect.throws(() => c.usePrivateKeySync(null), argumentError);
+    Expect.throws(() => c.usePrivateKey(1), argumentOrTypeError);
+    Expect.throws(() => c.usePrivateKey(null), argumentError);
     Expect.throws(() => c.usePrivateKeyBytes(1), argumentOrTypeError);
     Expect.throws(() => c.usePrivateKeyBytes(null), argumentError);
 
     // Too-long passwords.
-    Expect.throws(() => c.usePrivateKeySync(
+    Expect.throws(() => c.usePrivateKey(
         localFile('certificates/server_key.pem'), password: "dart" * 1000),
         argumentError);
-    Expect.throws(() => c.usePrivateKeySync(
+    Expect.throws(() => c.usePrivateKey(
         localFile('certificates/server_key.p12'), password: "dart" * 1000),
         argumentOrTypeError);
-    Expect.throws(() => c.setTrustedCertificatesSync(
+    Expect.throws(() => c.setTrustedCertificates(
         localFile('certificates/server_key.p12'), password: "dart" * 1000),
         argumentOrTypeError);
-    Expect.throws(() => c.useCertificateChainSync(
+    Expect.throws(() => c.useCertificateChain(
         localFile('certificates/server_key.p12'), password: "dart" * 1000),
         argumentOrTypeError);
-    Expect.throws(() => c.setClientAuthoritiesSync(
+    Expect.throws(() => c.setClientAuthorities(
         localFile('certificates/server_key.p12'), password: "dart" * 1000),
         argumentOrTypeError);
 
     // Bad password type.
-    Expect.throws(() => c.usePrivateKeySync(
+    Expect.throws(() => c.usePrivateKey(
         localFile('certificates/server_key.pem'), password: 3),
         argumentOrTypeError);
     Expect.throws(() => c.setTrustedCertificatesBytes(
@@ -100,24 +100,24 @@
     Expect.throws(() => c.setClientAuthoritiesBytes([]), argumentError);
 
     // Malformed PEM certs.
-    Expect.throws(() => c.usePrivateKeySync(
+    Expect.throws(() => c.usePrivateKey(
         localFile('certificates/client1_key_malformed.pem'),
         password: "dartdart"),
         tlsException);
-    Expect.throws(() => c.setTrustedCertificatesSync(
+    Expect.throws(() => c.setTrustedCertificates(
         localFile('certificates/trusted_certs_malformed.pem')),
         tlsException);
-    Expect.throws(() => c.useCertificateChainSync(
+    Expect.throws(() => c.useCertificateChain(
         localFile('certificates/server_chain_malformed1.pem')),
         tlsException);
-    Expect.throws(() => c.useCertificateChainSync(
+    Expect.throws(() => c.useCertificateChain(
         localFile('certificates/server_chain_malformed2.pem')),
         tlsException);
-    Expect.throws(() => c.setClientAuthoritiesSync(
+    Expect.throws(() => c.setClientAuthorities(
         localFile('certificates/client_authority_malformed.pem')),
         argumentError);
 
-    c.usePrivateKeySync(
+    c.usePrivateKey(
         localFile('certificates/server_key.pem'), password: "dartdart");
 }
 
diff --git a/tests/standalone/io/socket_upgrade_to_secure_test.dart b/tests/standalone/io/socket_upgrade_to_secure_test.dart
index aa5eca0..b4c862b 100644
--- a/tests/standalone/io/socket_upgrade_to_secure_test.dart
+++ b/tests/standalone/io/socket_upgrade_to_secure_test.dart
@@ -18,12 +18,12 @@
 List<int> readLocalFile(path) => (new File(localFile(path))).readAsBytesSync();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
-  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
-                      password: 'dartdart');
+  ..useCertificateChain(localFile('certificates/server_chain.pem'))
+  ..usePrivateKey(localFile('certificates/server_key.pem'),
+                  password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
 
 // This test creates a server and a client connects. After connecting
 // and an optional initial handshake the connection is secured by
diff --git a/tests/standalone/io/web_socket_compression_test.dart b/tests/standalone/io/web_socket_compression_test.dart
index c2f87ec..e25bc1b 100644
--- a/tests/standalone/io/web_socket_compression_test.dart
+++ b/tests/standalone/io/web_socket_compression_test.dart
@@ -25,9 +25,9 @@
 String localFile(path) => Platform.script.resolve(path).toFilePath();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
-  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
-                      password: 'dartdart');
+  ..useCertificateChain(localFile('certificates/server_chain.pem'))
+  ..usePrivateKey(localFile('certificates/server_key.pem'),
+                  password: 'dartdart');
 
 class SecurityConfiguration {
   final bool secure;
diff --git a/tests/standalone/io/web_socket_error_test.dart b/tests/standalone/io/web_socket_error_test.dart
index 31969a3..42b93d4 100644
--- a/tests/standalone/io/web_socket_error_test.dart
+++ b/tests/standalone/io/web_socket_error_test.dart
@@ -28,12 +28,12 @@
 String localFile(path) => Platform.script.resolve(path).toFilePath();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
-  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
-                      password: 'dartdart');
+  ..useCertificateChain(localFile('certificates/server_chain.pem'))
+  ..usePrivateKey(localFile('certificates/server_key.pem'),
+                  password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
 
 /**
  * A SecurityConfiguration lets us run the tests over HTTP or HTTPS.
diff --git a/tests/standalone/io/web_socket_test.dart b/tests/standalone/io/web_socket_test.dart
index e8642f5..f7ff673 100644
--- a/tests/standalone/io/web_socket_test.dart
+++ b/tests/standalone/io/web_socket_test.dart
@@ -24,12 +24,12 @@
 String localFile(path) => Platform.script.resolve(path).toFilePath();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
-  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
-                      password: 'dartdart');
+  ..useCertificateChain(localFile('certificates/server_chain.pem'))
+  ..usePrivateKey(localFile('certificates/server_key.pem'),
+                  password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
 
 /**
  * A SecurityConfiguration lets us run the tests over HTTP or HTTPS.
diff --git a/tests/standalone/map_literal_oom_test.dart b/tests/standalone/map_literal_oom_test.dart
index fb23497..955a499 100644
--- a/tests/standalone/map_literal_oom_test.dart
+++ b/tests/standalone/map_literal_oom_test.dart
Binary files differ
diff --git a/tests/standalone/noopt_test.dart b/tests/standalone/noopt_test.dart
deleted file mode 100644
index 171f3a5..0000000
--- a/tests/standalone/noopt_test.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-/// VMOptions=--noopt
-
-main() {
-  print("Hello, --noopt World!");
-}
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index 6b9e9e9..41f4d09 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -68,7 +68,6 @@
 verbose_gc_to_bmu_test: Skip
 precompilation_test: Skip # Standalone only test.
 precompilation_dart2js_test: Skip # Standalone only test.
-noopt_test: Skip # Standalone only test.
 
 [ $compiler == dartanalyzer || $compiler == dart2analyzer ]
 issue14236_test: Skip # Analyzer can't handle Script snapshots.
@@ -108,22 +107,17 @@
 pair_location_remapping_test: Skip
 precompilation_test: Skip # Standalone only test.
 precompilation_dart2js_test: Skip # Standalone only test.
-noopt_test: Skip # Standalone only test.
 regress_25335_test: Skip # Int64List not supported.
 
 [ ($runtime == vm || $runtime == dart_product) && $mode == debug ]
 precompilation_dart2js_test: Pass, Slow
 
 [ ($runtime == vm || $runtime == dart_product) && $arch == ia32 ]
-precompilation_test: Skip # Not expected to pass on ia32.
-precompilation_dart2js_test: Skip # Not expected to pass on ia32.
-noopt_test: Skip # Not expected to pass on ia32.
+precompilation_test: SkipByDesign # Not expected to pass on ia32.
+precompilation_dart2js_test: SkipByDesign # Not expected to pass on ia32.
 
-[ ($runtime == vm || $runtime == dart_product) && $arch == arm ]
-precompilation_test: Skip # Issue 24427
-precompilation_dart2js_test: Skip # Issue 24427
-
-[ ($runtime == vm || $runtime == dart_product) && $arch == mips ]
+[ ($runtime == vm || $runtime == dart_product) && ($arch == mips || $arch == arm || $arch == arm64) ]
+precompilation_test: SkipSlow
 precompilation_dart2js_test: SkipSlow
 
 [ $compiler == dart2js && $jscl ]
@@ -217,10 +211,13 @@
 no_allow_absolute_addresses_test: SkipByDesign # Not supported.
 link_natives_lazily_test: SkipByDesign # Not supported.
 
-[ ($noopt || $compiler == precompiler) ]
+[ $noopt || $compiler == precompiler ]
+# Stacktraces in precompilation omit inlined frames.
+assert_test: Pass, RuntimeError
+
+[ $noopt || $compiler == precompiler ]
 map_literal_oom_test: Pass, Crash # Issue 24678
 io/web_socket_test: Pass, RuntimeError # Issue 24674
-assert_test: RuntimeError # Expects line and column numbers
 precompilation_test: Skip # Platform.executable
 precompilation_dart2js_test: Skip  # Platform.executable
 io/test_extension_test: Skip # Platform.executable
@@ -237,7 +234,6 @@
 
 [ $runtime == dart_precompiled || $runtime == dart_product ]
 debugger/*: Skip
-noopt_test: Skip
 precompilation_test: Skip # Platform.executable
 precompilation_dart2js_test: Skip # Platform.executable
 full_coverage_test: Skip # Platform.executable
@@ -275,7 +271,6 @@
 io/test_extension_test: Skip # Platform.executable
 io/regress_7679_test: Skip # Platform.executable
 io/process_*: Skip # Most use Platform.executable
-assert_test: RuntimeError # Expects line and column numbers
 
 # Code coverage is not supported in product mode.
 [ $mode == product ]
diff --git a/tests/utils/utils.status b/tests/utils/utils.status
index 992eeb2..4ca122e 100644
--- a/tests/utils/utils.status
+++ b/tests/utils/utils.status
@@ -22,5 +22,5 @@
 [ $compiler == dart2js && $mode == debug ]
 dummy_compiler_test: Slow, Pass
 
-[ ($noopt || $compiler == precompiler || $compiler == dart2app) ]
+[ $noopt || $compiler == precompiler || $compiler == dart2app ]
 source_mirrors_test: SkipByDesign # Imports dart:mirrors
diff --git a/tools/VERSION b/tools/VERSION
index 888fdb3..42b3a94 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 1
 MINOR 15
 PATCH 0
-PRERELEASE 4
+PRERELEASE 5
 PRERELEASE_PATCH 0
diff --git a/tools/deps/dartium.deps/DEPS b/tools/deps/dartium.deps/DEPS
index a510fd4..0105c11 100644
--- a/tools/deps/dartium.deps/DEPS
+++ b/tools/deps/dartium.deps/DEPS
@@ -9,7 +9,7 @@
 
 vars.update({
   "dartium_chromium_commit": "8df9de5a8f073d9c0feadf8d652408807e4a254e",
-  "dartium_webkit_commit": "1d73225937ba77bba2d4279fe7b23bfb542d35d9",
+  "dartium_webkit_commit": "28b9a6c03797eaecf6c92677cba747eb9df0787c",
   "chromium_base_revision": "338390",
 
   # We use mirrors of all github repos to guarantee reproducibility and
diff --git a/tools/dom/idl/dart/dart.idl b/tools/dom/idl/dart/dart.idl
index f63ad18..bf857a8 100644
--- a/tools/dom/idl/dart/dart.idl
+++ b/tools/dom/idl/dart/dart.idl
@@ -142,47 +142,6 @@
                               optional DOMString statusMessageArg);
 };
 
-[DartSupplemental]
-interface WebGLRenderingContext {
-
-  //void         compressedTexImage2D(unsigned long target, long level, unsigned long internalformat, unsigned long width, unsigned long height, long border, unsigned long imageSize, const void* data);
-  //void         compressedTexSubImage2D(unsigned long target, long level, long xoffset, long yoffset, unsigned long width, unsigned long height, unsigned long format, unsigned long imageSize, const void* data);
-
-  [Custom] any getBufferParameter(unsigned long target, unsigned long pname);
-  [DartSuppress, DartStrictTypeChecking, Custom] void getBufferParameter();
-
-  [Custom] any getFramebufferAttachmentParameter(unsigned long target, unsigned long attachment, unsigned long pname);
-  [DartSuppress, DartStrictTypeChecking, Custom] void getFramebufferAttachmentParameter();
-
-  [Custom] any getParameter(unsigned long pname);
-  [DartSuppress, DartStrictTypeChecking, Custom] void getParameter();
-
-  [Custom] any getProgramParameter(WebGLProgram program, unsigned long pname);
-  [DartSuppress, DartStrictTypeChecking, Custom] void getProgramParameter();
-
-  [Custom] any getRenderbufferParameter(unsigned long target, unsigned long pname);
-  [DartSuppress, DartStrictTypeChecking, Custom] void getRenderbufferParameter();
-
-  [Custom] any getShaderParameter(WebGLShader shader, unsigned long pname);
-  [DartSuppress, DartStrictTypeChecking, Custom] void getShaderParameter();
-
-  // TBD
-  // void glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision);
-
-  [Custom] any getExtension(DOMString name);
-  [DartSuppress, DartStrictTypeChecking, Custom] void getExtension(DOMString name);
-  [DartSuppress, DartStrictTypeChecking, Custom] void getSupportedExtensions();
-
-  [Custom] any getTexParameter(unsigned long target, unsigned long pname);
-  [DartSuppress, DartStrictTypeChecking, Custom] void getTexParameter();
-
-  [Custom] any getUniform(WebGLProgram program, WebGLUniformLocation location);
-  [DartSuppress, DartStrictTypeChecking, Custom] void getUniform();
-
-  [Custom] any getVertexAttrib(unsigned long index, unsigned long pname);
-  [DartSuppress, DartStrictTypeChecking, Custom] void getVertexAttrib();
-};
-
 // TODO(vsm): Define new names for these (see b/4436830).
 [DartSupplemental]
 interface IDBCursor {
@@ -210,9 +169,6 @@
 interface IDBObjectStore {
     [CallWith=ScriptState, RaisesException] IDBRequest put(any value, [DartForceOptional] optional any key);
     [CallWith=ScriptState, RaisesException] IDBRequest add(any value, [DartForceOptional] optional any key);
-    // [CallWith=ExecutionContext, ImplementedAs=deleteFunction, RaisesException] IDBRequest delete(any key);
-    [CallWith=ExecutionContext, RaisesException] IDBRequest openCursor([Default=Undefined] optional any range, [DartForceOptional] optional DOMString direction);
-    [CallWith=ExecutionContext, RaisesException] IDBRequest count([Default=Undefined] any key);
 };
 
 interface EntrySync {
diff --git a/tools/dom/scripts/dartdomgenerator.py b/tools/dom/scripts/dartdomgenerator.py
index cacdd63..8194dfc 100755
--- a/tools/dom/scripts/dartdomgenerator.py
+++ b/tools/dom/scripts/dartdomgenerator.py
@@ -106,7 +106,7 @@
                              exclude_suppressed = ['WebKit', 'Dart'])
   generator.FixEventTargets(webkit_database)
   generator.AddMissingArguments(webkit_database)
-  generator.HackCleanupTimers(webkit_database)
+  generator.CleanupOperationArguments(webkit_database)
 
   emitters = multiemitter.MultiEmitter(logging_level)
   metadata = DartMetadata(
diff --git a/tools/dom/scripts/dartgenerator.py b/tools/dom/scripts/dartgenerator.py
index 5adbe3a..e3e9625 100755
--- a/tools/dom/scripts/dartgenerator.py
+++ b/tools/dom/scripts/dartgenerator.py
@@ -12,6 +12,7 @@
 import re
 import shutil
 from generator import *
+from idlnode import IDLType
 
 _logger = logging.getLogger('dartgenerator')
 
@@ -245,10 +246,17 @@
         if 'ScriptArguments' in call_with:
           operation.arguments.append(ARG)
 
-  # TODO(terry): Hack to remove 3rd arguments in setInterval/setTimeout.
-  def HackCleanupTimers(self, database):
+  def CleanupOperationArguments(self, database):
     for interface in database.GetInterfaces():
       for operation in interface.operations:
+        # TODO(terry): Hack to remove 3rd arguments in setInterval/setTimeout.
         if ((operation.id == 'setInterval' or operation.id == 'setTimeout') and \
             operation.arguments[0].type.id == 'any'):
           operation.arguments.pop(2)
+
+        # Massage any operation argument type that is IDLEnum to String.
+        for index, argument in enumerate(operation.arguments):
+          type_name = argument.type.id
+          if database.HasEnum(type_name):
+            operation.arguments[index].type = IDLType('DOMString')
+
diff --git a/tools/dom/scripts/database.py b/tools/dom/scripts/database.py
index 19ca222..7329b22 100755
--- a/tools/dom/scripts/database.py
+++ b/tools/dom/scripts/database.py
@@ -314,24 +314,30 @@
     The list contains the interface objects for interfaces defined in the
     database, and the name for undefined interfaces.
     """
-    def walk(parents):
+    def walk(parents, walk_result):
       for parent in parents:
         parent_name = parent.type.id
         if IsDartCollectionType(parent_name):
-          result.append(parent_name)
+          if not(parent_name in walk_result):
+            walk_result.append(parent_name)
           continue
         if self.HasInterface(parent_name):
           parent_interface = self.GetInterface(parent_name)
-          result.append(parent_interface)
-          walk(parent_interface.parents)
+          if not(parent_interface in walk_result):
+            # Interface has multi-inherited don't add interfaces more than once
+            # to our parent result list.
+            walk_result.append(parent_interface)
+          walk(parent_interface.parents, walk_result)
+      return walk_result
 
     result = []
     if interface.parents:
       parent = interface.parents[0]
       if (IsPureInterface(parent.type.id) or
           (propagate_event_target and parent.type.id == 'EventTarget')):
-        walk(interface.parents)
+        result = walk(interface.parents, [])
       else:
-        walk(interface.parents[1:])
+        result = walk(interface.parents[1:], [])
+
     return result
 
diff --git a/tools/dom/scripts/generate_blink_file.py b/tools/dom/scripts/generate_blink_file.py
index a45b9ac..6f274da 100644
--- a/tools/dom/scripts/generate_blink_file.py
+++ b/tools/dom/scripts/generate_blink_file.py
@@ -158,6 +158,18 @@
 ARGUMENT_NUM = "__arg_%s"
 OPERATION_ARGS = '  %s_Callback_%s_(mthis, %s) => Blink_JsNative_DomException.callMethod(mthis, "%s", [%s]);\n\n'
 
+# get class property to make static call.
+CLASS_STATIC = 'Blink_JsNative_DomException.getProperty(js.context, "%s")'
+
+# name, classname_getproperty, name
+STATIC_ATTRIBUTE_GETTER = '  %s_Getter_() => Blink_JsNative_DomException.getProperty(%s, "%s");\n\n'
+
+# name, classname_getproperty, name
+STATIC_OPERATION_0 = '  %s_Callback_0_() => Blink_JsNative_DomException.callMethod(%s, "%s", []);\n\n'
+
+# name, argsCount, args, classname_getproperty, name, args
+STATIC_OPERATION_ARGS = '  %s_Callback_%s_(%s) => Blink_JsNative_DomException.callMethod(%s, "%s", [%s]);\n\n'
+
 CLASS_DEFINITION_END = """}
 
 """
@@ -179,6 +191,7 @@
 
 constructor_renames = {
     'RTCPeerConnection': 'webkitRTCPeerConnection',
+    'SpeechRecognition': 'webkitSpeechRecognition',
 }
 
 def rename_constructor(name):
@@ -215,12 +228,12 @@
       # Zero parameter constructor.
       blink_file.write(CONSTRUCTOR_0 % rename_constructor(name))
 
-    _Process_Attributes(blink_file, interface.attributes)
+    _Process_Attributes(blink_file, interface, interface.attributes)
     _Process_Operations(blink_file, interface, interface.operations)
 
     secondary_parents = database.TransitiveSecondaryParents(interface, False)
     for secondary in secondary_parents:
-      _Process_Attributes(blink_file, secondary.attributes)
+      _Process_Attributes(blink_file, secondary, secondary.attributes)
       _Process_Operations(blink_file, secondary, secondary.operations)
 
     blink_file.write(CLASS_DEFINITION_END);
@@ -245,12 +258,16 @@
       argument_list = ', '.join(arguments)
       blink_file.write(CONSTRUCTOR_ARGS % (callback_index, argument_list, rename_constructor(name), argument_list))
 
-def _Process_Attributes(blink_file, attributes):
+def _Process_Attributes(blink_file, interface, attributes):
   # Emit an interface's attributes and operations.
   for attribute in sorted(attributes, ConstantOutputOrder):
     name = attribute.id
     if attribute.is_read_only:
-      blink_file.write(ATTRIBUTE_GETTER % (name, name))
+      if attribute.is_static:
+        class_property = CLASS_STATIC % interface.id
+        blink_file.write(STATIC_ATTRIBUTE_GETTER % (name, class_property, name))
+      else:
+        blink_file.write(ATTRIBUTE_GETTER % (name, name))
     else:
       blink_file.write(ATTRIBUTE_GETTER % (name, name))
       blink_file.write(ATTRIBUTE_SETTER % (name, name))
@@ -297,10 +314,18 @@
 
   for callback_index in range(arg_min_count, arg_max_count):
     if callback_index == 0:
-      blink_file.write(OPERATION_0 % (name, name))
+      if operation.is_static:
+        class_property = CLASS_STATIC % interface.id
+        blink_file.write(STATIC_OPERATION_0 % (name, class_property, name))
+      else:
+        blink_file.write(OPERATION_0 % (name, name))
     else:
       arguments = []
       for i in range(0, callback_index):
         arguments.append(ARGUMENT_NUM % i)
       argument_list = ', '.join(arguments)
-      blink_file.write(OPERATION_ARGS % (name, callback_index, argument_list, name, argument_list))
+      if operation.is_static:
+        class_property = CLASS_STATIC % interface.id
+        blink_file.write(STATIC_OPERATION_ARGS % (name, callback_index, argument_list, class_property, name, argument_list))
+      else:
+        blink_file.write(OPERATION_ARGS % (name, callback_index, argument_list, name, argument_list))
diff --git a/tools/dom/scripts/generator.py b/tools/dom/scripts/generator.py
index a1ebfe2..a5488b2 100644
--- a/tools/dom/scripts/generator.py
+++ b/tools/dom/scripts/generator.py
@@ -141,7 +141,7 @@
         'ApplicationCache,DOMApplicationCache,OfflineResourceList',
 
     'Event':
-        'Event,InputEvent,ClipboardEvent',
+        'Event,InputEvent',
 
     'HTMLTableCellElement':
         'HTMLTableCellElement,HTMLTableDataCellElement,HTMLTableHeaderCellElement',
@@ -151,7 +151,7 @@
     'IDBOpenDBRequest':
         'IDBOpenDBRequest,IDBVersionChangeRequest',
 
-    'MouseEvent': 'MouseEvent,DragEvent,PointerEvent,MSPointerEvent',
+    'MouseEvent': 'MouseEvent,DragEvent',
 
     'MutationObserver': 'MutationObserver,WebKitMutationObserver',
 
@@ -1264,6 +1264,9 @@
     # TODO(vsm): This won't actually work until we convert the Map to
     # a native JS Map for JS DOM.
     'Dictionary': TypeData(clazz='Primitive', dart_type='Map'),
+    # TODO(terry): It's a dictionary but a very complex dictionary is multiple lists.
+    #              Need to investigate a 1-off solution probably.
+    'MediaKeySystemConfiguration': TypeData(clazz='Primitive', dart_type='Map'),
     'DOMTimeStamp': TypeData(clazz='Primitive', dart_type='int', native_type='unsigned long long'),
     'object': TypeData(clazz='Primitive', dart_type='Object', native_type='ScriptValue'),
     'ObjectArray': TypeData(clazz='Primitive', dart_type='List'),
@@ -1309,6 +1312,22 @@
         suppress_interface=True),
     'GLenum': TypeData(clazz='Primitive', dart_type='int',
         native_type='unsigned'),
+    'GLboolean': TypeData(clazz='Primitive', dart_type='bool',
+        native_type='bool'),
+    'GLbitfield': TypeData(clazz='Primitive', dart_type='int',
+        native_type='unsigned'),
+    'GLshort': TypeData(clazz='Primitive', dart_type='int', native_type='short'),
+    'GLint': TypeData(clazz='Primitive', dart_type='int',
+        native_type='long'),
+    'GLsizei': TypeData(clazz='Primitive', dart_type='int',
+        native_type='long'),
+    'GLintptr': TypeData(clazz='Primitive', dart_type='int'),
+    'GLsizeiptr': TypeData(clazz='Primitive', dart_type='int'),
+    'GLushort': TypeData(clazz='Primitive', dart_type='int', native_type='int'),
+    'GLuint': TypeData(clazz='Primitive', dart_type='int',
+        native_type='unsigned'),
+    'GLfloat': TypeData(clazz='Primitive', dart_type='num', native_type='float'),
+    'GLclampf': TypeData(clazz='Primitive', dart_type='num', native_type='float'),
     'HTMLCollection': TypeData(clazz='Interface', item_type='Node',
         dart_type='List<Node>'),
     'NamedNodeMap': TypeData(clazz='Interface', item_type='Node'),
diff --git a/tools/dom/scripts/htmlrenamer.py b/tools/dom/scripts/htmlrenamer.py
index b05f9cc..addddd9 100644
--- a/tools/dom/scripts/htmlrenamer.py
+++ b/tools/dom/scripts/htmlrenamer.py
@@ -268,10 +268,6 @@
   'Element.scrollTop',
   'Element.scrollWidth',
   'Element.scrollHeight',
-  'Element.clientLeft',
-  'Element.clientTop',
-  'Element.clientWidth',
-  'Element.clientHeight',
 
   'Event.initEvent',
   'EventTarget.addEventListener',
@@ -832,13 +828,6 @@
     'NodeList.item',
     'ParentNode.append',
     'ParentNode.prepend',
-    'Performance.webkitClearMarks',
-    'Performance.webkitClearMeasures',
-    'Performance.webkitGetEntries',
-    'Performance.webkitGetEntriesByName',
-    'Performance.webkitGetEntriesByType',
-    'Performance.webkitMark',
-    'Performance.webkitMeasure',
     'ShadowRoot.getElementsByTagNameNS',
     'SVGElement.getPresentationAttribute',
     'SVGElementInstance.on:wheel',
diff --git a/tools/dom/scripts/idlnode.py b/tools/dom/scripts/idlnode.py
index b5949a3..2d81988 100755
--- a/tools/dom/scripts/idlnode.py
+++ b/tools/dom/scripts/idlnode.py
@@ -12,6 +12,23 @@
 
 new_asts = {}
 
+# Ugly but Chrome IDLs can reference typedefs in any IDL w/o an include.  So we
+# need to remember any typedef seen then alias any reference to a typedef.
+typeDefsFixup = []
+
+def _resolveTypedef(type):
+  """ Given a type if it's a known typedef (only typedef's that aren't union)
+      are remembered for fixup.  typedefs that are union type are mapped to
+      any so those we don't need to alias.  typedefs referenced in the file
+      where the typedef was defined are automatically aliased to the real type.
+      This resolves typedef where the declaration is in another IDL file.
+  """
+  for typedef in typeDefsFixup:
+    if typedef.id == type.id:
+      return typedef.type
+
+  return type
+
 
 _operation_suffix_map = {
   '__getter__': "Getter",
@@ -406,6 +423,9 @@
       elif typedef_type.idl_type.base_type == 'Dictionary':
         dictionary = IDLDictionary(typedef_type, True)
         self.dictionaries.append(dictionary)
+      else:
+        # All other typedefs we record
+        typeDefsFixup.append(IDLTypeDef(typedef_type))
 
     self.enums = self._convert_all(ast, 'Enum', IDLEnum)
 
@@ -538,79 +558,80 @@
   def __init__(self, ast):
     IDLNode.__init__(self, ast)
 
-    self.nullable = self._has(ast, 'Nullable')
-    # Search for a 'ScopedName' or any label ending with 'Type'.
-    if isinstance(ast, list):
-      self.id = self._find_first(ast, 'ScopedName')
-      if not self.id:
-        # FIXME: use regexp search instead
-        def findType(ast):
-          for label, childAst in ast:
-            if label.endswith('Type'):
-              type = self._label_to_type(label, ast)
-              if type != 'sequence':
-                return type
-              type_ast = self._find_first(childAst, 'Type')
-              if not type_ast:
-                return type
-              return 'sequence<%s>' % findType(type_ast)
-          raise Exception('No type declaration found in %s' % ast)
-        self.id = findType(ast)
-      # TODO(terry): Remove array_modifiers id has [] appended, keep for old
-      #              parsing.
-      array_modifiers = self._find_first(ast, 'ArrayModifiers')
-      if array_modifiers:
-        self.id += array_modifiers
-    elif isinstance(ast, tuple):
-      (label, value) = ast
-      if label == 'ScopedName':
-        self.id = value
-      else:
-        self.id = self._label_to_type(label, ast)
-    elif isinstance(ast, str):
-      self.id = ast
-    # New blink handling.
-    elif ast.__module__ == "idl_types":
-      if isinstance(ast, IdlType) or isinstance(ast, IdlArrayOrSequenceType) or \
-         isinstance(ast, IdlNullableType):
-        if isinstance(ast, IdlNullableType) and ast.inner_type.is_union_type:
-          print 'WARNING type %s is union mapped to \'any\'' % self.id
+    if ast:
+      self.nullable = self._has(ast, 'Nullable')
+      # Search for a 'ScopedName' or any label ending with 'Type'.
+      if isinstance(ast, list):
+        self.id = self._find_first(ast, 'ScopedName')
+        if not self.id:
+          # FIXME: use regexp search instead
+          def findType(ast):
+            for label, childAst in ast:
+              if label.endswith('Type'):
+                type = self._label_to_type(label, ast)
+                if type != 'sequence':
+                  return type
+                type_ast = self._find_first(childAst, 'Type')
+                if not type_ast:
+                  return type
+                return 'sequence<%s>' % findType(type_ast)
+            raise Exception('No type declaration found in %s' % ast)
+          self.id = findType(ast)
+        # TODO(terry): Remove array_modifiers id has [] appended, keep for old
+        #              parsing.
+        array_modifiers = self._find_first(ast, 'ArrayModifiers')
+        if array_modifiers:
+          self.id += array_modifiers
+      elif isinstance(ast, tuple):
+        (label, value) = ast
+        if label == 'ScopedName':
+          self.id = value
+        else:
+          self.id = self._label_to_type(label, ast)
+      elif isinstance(ast, str):
+        self.id = ast
+      # New blink handling.
+      elif ast.__module__ == "idl_types":
+        if isinstance(ast, IdlType) or isinstance(ast, IdlArrayOrSequenceType) or \
+           isinstance(ast, IdlNullableType):
+          if isinstance(ast, IdlNullableType) and ast.inner_type.is_union_type:
+            print 'WARNING type %s is union mapped to \'any\'' % self.id
+            # TODO(terry): For union types use any otherwise type is unionType is
+            #              not found and is removed during merging.
+            self.id = 'any'
+          else:
+            type_name = str(ast)
+            # TODO(terry): For now don't handle unrestricted types see
+            #              https://code.google.com/p/chromium/issues/detail?id=354298
+            type_name = type_name.replace('unrestricted ', '', 1);
+  
+            # TODO(terry): Handled USVString as a DOMString.
+            type_name = type_name.replace('USVString', 'DOMString', 1)
+  
+            # TODO(terry); WindowTimers setInterval/setTimeout overloads with a
+            #              Function type - map to any until the IDL uses union.
+            type_name = type_name.replace('Function', 'any', 1)
+  
+            self.id = type_name
+        else:
+          # IdlUnionType
+          if ast.is_union_type:
+            print 'WARNING type %s is union mapped to \'any\'' % self.id
           # TODO(terry): For union types use any otherwise type is unionType is
           #              not found and is removed during merging.
-          self.id = 'any'
-        else:
-          type_name = str(ast)
-          # TODO(terry): For now don't handle unrestricted types see
-          #              https://code.google.com/p/chromium/issues/detail?id=354298
-          type_name = type_name.replace('unrestricted ', '', 1);
-
-          # TODO(terry): Handled USVString as a DOMString.
-          type_name = type_name.replace('USVString', 'DOMString', 1)
-
-          # TODO(terry); WindowTimers setInterval/setTimeout overloads with a
-          #              Function type - map to any until the IDL uses union.
-          type_name = type_name.replace('Function', 'any', 1)
-
-          self.id = type_name
-      else:
-        # IdlUnionType
-        if ast.is_union_type:
-          print 'WARNING type %s is union mapped to \'any\'' % self.id
-        # TODO(terry): For union types use any otherwise type is unionType is
-        #              not found and is removed during merging.
-          self.id = 'any'
-        # TODO(terry): Any union type e.g. 'type1 or type2 or type2',
-        #                            'typedef (Type1 or Type2) UnionType'
-        # Is a problem we need to extend IDLType and IDLTypeDef to handle more
-        # than one type.
-        #
-        # Also for typedef's e.g.,
-        #                 typedef (Type1 or Type2) UnionType
-        # should consider synthesizing a new interface (e.g., UnionType) that's
-        # both Type1 and Type2.
-    if not self.id:
-      print '>>>> __module__ %s' % ast.__module__
-      raise SyntaxError('Could not parse type %s' % (ast))
+            self.id = 'any'
+          # TODO(terry): Any union type e.g. 'type1 or type2 or type2',
+          #                            'typedef (Type1 or Type2) UnionType'
+          # Is a problem we need to extend IDLType and IDLTypeDef to handle more
+          # than one type.
+          #
+          # Also for typedef's e.g.,
+          #                 typedef (Type1 or Type2) UnionType
+          # should consider synthesizing a new interface (e.g., UnionType) that's
+          # both Type1 and Type2.
+      if not self.id:
+        print '>>>> __module__ %s' % ast.__module__
+        raise SyntaxError('Could not parse type %s' % (ast))
 
   def _label_to_type(self, label, ast):
     if label == 'LongLongType':
@@ -747,6 +768,8 @@
     IDLNode.__init__(self, ast)
 
     self.type = self._convert_first(ast, 'Type', IDLType)
+    self.type = _resolveTypedef(self.type)
+
     self._convert_ext_attrs(ast)
     self._convert_annotations(ast)
     self.doc_js_interface_name = doc_js_interface_name
@@ -755,13 +778,13 @@
                             'DartSuppress' in self.ext_attrs
     self.is_static = self._has(ast, 'Static')
 
-
 class IDLOperation(IDLMember):
   """IDLNode specialization for 'type name(args)' declarations."""
   def __init__(self, ast, doc_js_interface_name):
     IDLMember.__init__(self, ast, doc_js_interface_name)
 
     self.type = self._convert_first(ast, 'ReturnType', IDLType)
+    self.type = _resolveTypedef(self.type)
     self.arguments = self._convert_all(ast, 'Argument', IDLArgument)
     self.specials = self._find_all(ast, 'Special')
     # Special case: there are getters of the form
@@ -839,6 +862,8 @@
         self.default_value_is_null = False
 
     self.type = self._convert_first(ast, 'Type', IDLType)
+    self.type = _resolveTypedef(self.type)
+
     self.optional = self._has(ast, 'Optional')
     self._convert_ext_attrs(ast)
     # TODO(vsm): Recover this from the type instead.
diff --git a/tools/dom/templates/html/impl/impl_CanvasRenderingContext2D.darttemplate b/tools/dom/templates/html/impl/impl_CanvasRenderingContext2D.darttemplate
index 9173eff..cd5fa3c 100644
--- a/tools/dom/templates/html/impl/impl_CanvasRenderingContext2D.darttemplate
+++ b/tools/dom/templates/html/impl/impl_CanvasRenderingContext2D.darttemplate
@@ -11,6 +11,15 @@
 $(ANNOTATIONS)$(NATIVESPEC)$(CLASS_MODIFIERS)class $CLASSNAME$EXTENDS implements CanvasRenderingContext {
 $!MEMBERS
 
+  @DomName('CanvasRenderingContext2D.createImageDataFromImageData')
+  @DocsEditable()
+  ImageData createImageDataFromImageData(ImageData imagedata) =>
+$if DART2JS
+    JS('ImageData', '#.createImageData(#, #)', this, imagedata);
+$else
+    this.createImageData(imagedata);
+$endif
+
   /**
    * Sets the color used inside shapes.
    * [r], [g], [b] are 0-255, [a] is 0-1.
diff --git a/tools/dom/templates/html/impl/impl_Element.darttemplate b/tools/dom/templates/html/impl/impl_Element.darttemplate
index a4ddc94..4b8173b 100644
--- a/tools/dom/templates/html/impl/impl_Element.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Element.darttemplate
@@ -1540,22 +1540,6 @@
   @DocsEditable()
   int get offsetWidth => JS('num', '#.offsetWidth', this).round();
 
-  @DomName('Element.clientHeight')
-  @DocsEditable()
-  int get clientHeight => JS('num', '#.clientHeight', this).round();
-
-  @DomName('Element.clientLeft')
-  @DocsEditable()
-  int get clientLeft => JS('num', '#.clientLeft', this).round();
-
-  @DomName('Element.clientTop')
-  @DocsEditable()
-  int get clientTop => JS('num', '#.clientTop', this).round();
-
-  @DomName('Element.clientWidth')
-  @DocsEditable()
-  int get clientWidth => JS('num', '#.clientWidth', this).round();
-
   @DomName('Element.scrollHeight')
   @DocsEditable()
   int get scrollHeight => JS('num', '#.scrollHeight', this).round();
diff --git a/tools/dom/templates/html/impl/impl_MessageEvent.darttemplate b/tools/dom/templates/html/impl/impl_MessageEvent.darttemplate
index 1b3280d..fec4341 100644
--- a/tools/dom/templates/html/impl/impl_MessageEvent.darttemplate
+++ b/tools/dom/templates/html/impl/impl_MessageEvent.darttemplate
@@ -36,6 +36,22 @@
   @DocsEditable()
   dynamic get data => convertNativeToDart_SerializedScriptValue(
       _blink.BlinkMessageEvent.instance.data_Getter_(unwrap_jso(this)));
+
+$else
+  // TODO(alanknight): This really should be generated by the
+  // _OutputConversion in the systemnative.py script, but that doesn't
+  // use those conversions right now, so do this as a one-off.
+  @DomName('MessageEvent.data')
+  @DocsEditable()
+  dynamic get data => convertNativeToDart_SerializedScriptValue(this._get_data);
+
+  @JSName('data')
+  @DomName('MessageEvent.data')
+  @DocsEditable()
+  @Creates('Null')
+  @Returns('Object|Null')
+  final dynamic _get_data;
+
 $endif
 
 $!MEMBERS
diff --git a/tools/precompilation/precompiler.dart b/tools/precompilation/precompiler.dart
deleted file mode 100755
index 419875a..0000000
--- a/tools/precompilation/precompiler.dart
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library precompiler;
-
-import 'dart:io';
-
-void run(String executable, String arguments, [String workingDirectory]) {
-  print("+ $executable ${arguments.join(' ')}");
-  var result = Process.runSync(executable, arguments,
-                               workingDirectory: workingDirectory);
-  stdout.write(result.stdout);
-  stderr.write(result.stderr);
-  if (result.exitCode != 0) {
-    exit(result.exitCode);
-  }
-}
-
-void main(List<String> args) {
-  var configuration = Platform.environment["DART_CONFIGURATION"];
-
-  var cc, cc_flags, shared, libname;
-  if (Platform.isLinux) {
-    cc = 'gcc';
-    shared = '-shared';
-    libname = 'libprecompiled.so';
-  } else if (Platform.isMacOS) {
-    cc = 'clang';
-    shared = '-dynamiclib';
-    libname = 'libprecompiled.dylib';
-  } else {
-    print("Test only supports Linux and Mac");
-    return;
-  }
-
-  if (configuration.endsWith("X64")) {
-    cc_flags = "-m64";
-  } else if (configuration.endsWith("SIMARM64")) {
-    cc_flags = "-m64";
-  } else if (configuration.endsWith("SIMARM")) {
-    cc_flags = "-m32";
-  } else if (configuration.endsWith("SIMMIPS")) {
-    cc_flags = "-m32";
-  } else if (configuration.endsWith("ARM")) {
-    cc_flags = "";
-  } else if (configuration.endsWith("MIPS")) {
-    cc_flags = "-EL";
-  } else {
-    print("Architecture not supported: $configuration");
-    return;
-  }
-
-  var tmpDir;
-  for (var arg in args) {
-    if (arg.startsWith("--gen-precompiled-snapshot")) {
-      tmpDir = arg.substring("--gen-precompiled-snapshot".length + 1);
-    }
-  }
-  print("Using directory $tmpDir");
-
-  run(args[0], args.sublist(1));
-  run(cc, [shared, cc_flags, "-o", libname, "precompiled.S"], tmpDir);
-}
diff --git a/tools/testing/dart/compiler_configuration.dart b/tools/testing/dart/compiler_configuration.dart
index 931a53d..4794992 100644
--- a/tools/testing/dart/compiler_configuration.dart
+++ b/tools/testing/dart/compiler_configuration.dart
@@ -78,7 +78,8 @@
             isDebug: isDebug, isChecked: isChecked);
       case 'precompiler':
         return new PrecompilerCompilerConfiguration(
-            isDebug: isDebug, isChecked: isChecked);
+            isDebug: isDebug, isChecked: isChecked,
+            arch: configuration['arch']);
       case 'none':
         return new NoneCompilerConfiguration(
             isDebug: isDebug, isChecked: isChecked,
@@ -302,10 +303,13 @@
 
 
 class PrecompilerCompilerConfiguration extends CompilerConfiguration {
+  final String arch;
+
   PrecompilerCompilerConfiguration({
       bool isDebug,
-      bool isChecked})
-      : super._subclass(isDebug: isDebug, isChecked: isChecked);
+      bool isChecked,
+      String arch})
+    : super._subclass(isDebug: isDebug, isChecked: isChecked), arch = arch;
 
   int computeTimeoutMultiplier() {
     int multiplier = 2;
@@ -327,6 +331,18 @@
                 buildDir,
                 CommandBuilder.instance,
                 arguments,
+                environmentOverrides),
+            this.computeAssembleCommand(
+                tempDir,
+                buildDir,
+                CommandBuilder.instance,
+                arguments,
+                environmentOverrides),
+            this.computeRemoveAssemblyCommand(
+                tempDir,
+                buildDir,
+                CommandBuilder.instance,
+                arguments,
                 environmentOverrides)],
         '$tempDir',
         'application/dart-precompiled');
@@ -338,19 +354,91 @@
       CommandBuilder commandBuilder,
       List arguments,
       Map<String, String> environmentOverrides) {
-    var exec = "$buildDir/dart";
+    var exec = "$buildDir/dart_no_snapshot";
     var args = new List();
-    args.add("tools/precompilation/precompiler.dart");
-    args.add("$buildDir/dart_no_snapshot");
     args.add("--gen-precompiled-snapshot=$tempDir");
     args.addAll(arguments);
 
     return commandBuilder.getCompilationCommand(
-        'precompiler.dart', tempDir, !useSdk,
+        'precompiler', tempDir, !useSdk,
         bootstrapDependencies(buildDir),
         exec, args, environmentOverrides);
   }
 
+  CompilationCommand computeAssembleCommand(
+      String tempDir,
+      String buildDir,
+      CommandBuilder commandBuilder,
+      List arguments,
+      Map<String, String> environmentOverrides) {
+    var cc, cc_flags, shared, libname;
+    if (Platform.isLinux) {
+      cc = 'gcc';
+      shared = '-shared';
+      libname = 'libprecompiled.so';
+    } else if (Platform.isMacOS) {
+      cc = 'clang';
+      shared = '-dynamiclib';
+      libname = 'libprecompiled.dylib';
+    } else {
+      throw "Platform not supported: ${Platform.operatingSystem}";
+    }
+
+    if (arch == 'x64') {
+      cc_flags = "-m64";
+    } else if (arch == 'simarm64') {
+      cc_flags = "-m64";
+    } else if (arch == 'simarm') {
+      cc_flags = "-m32";
+    } else if (arch == 'simmips') {
+      cc_flags = "-m32";
+    } else if (arch == 'arm') {
+      cc_flags = "";
+    } else if (arch == 'mips') {
+      cc_flags = "-EL";
+    } else {
+      throw "Architecture not supported: $arch";
+    }
+
+    var exec = cc;
+    var args = [shared,
+                cc_flags,
+                '-o',
+                '$tempDir/$libname',
+                '$tempDir/precompiled.S'];
+
+    return commandBuilder.getCompilationCommand(
+        'assemble', tempDir, !useSdk,
+        bootstrapDependencies(buildDir),
+        exec, args, environmentOverrides);
+  }
+
+  // This step reduces the amount of space needed to run the precompilation
+  // tests by 60%.
+  CompilationCommand computeRemoveAssemblyCommand(
+      String tempDir,
+      String buildDir,
+      CommandBuilder commandBuilder,
+      List arguments,
+      Map<String, String> environmentOverrides) {
+    var exec = 'rm';
+    var args = ['$tempDir/precompiled.S'];
+
+    return commandBuilder.getCompilationCommand(
+        'remove_assembly', tempDir, !useSdk,
+        bootstrapDependencies(buildDir),
+        exec, args, environmentOverrides);
+  }
+
+  List<String> filterVmOptions(List<String> vmOptions) {
+    var filtered = new List.from(vmOptions);
+    filtered.removeWhere(
+      (option) => option.startsWith("--optimization-counter-threshold"));
+    filtered.removeWhere(
+      (option) => option.startsWith("--optimization_counter_threshold"));
+    return filtered;
+  }
+
   List<String> computeCompilerArguments(vmOptions,
                                         sharedOptions,
                                         originalArguments) {
@@ -360,7 +448,7 @@
       args.add('--enable_type_checks');
     }
     return args
-        ..addAll(vmOptions)
+        ..addAll(filterVmOptions(vmOptions))
         ..addAll(sharedOptions)
         ..addAll(originalArguments);
   }
@@ -405,35 +493,37 @@
       CommandBuilder commandBuilder,
       List arguments,
       Map<String, String> environmentOverrides) {
+    String outputName = computeOutputName(tempDir);
     return new CommandArtifact(
         <Command>[
             this.computeCompilationCommand(
-                tempDir,
+                outputName,
                 buildDir,
                 CommandBuilder.instance,
                 arguments,
                 environmentOverrides)],
-        computeOutputName(tempDir),
+        outputName,
         'application/dart-snapshot');
   }
 
   String computeOutputName(String tempDir) {
-    return '$tempDir/test.snapshot';
+    var randName = TestUtils.getRandomNumber().toString();
+    return '$tempDir/test.$randName';
   }
 
   CompilationCommand computeCompilationCommand(
-      String tempDir,
+      String outputName,
       String buildDir,
       CommandBuilder commandBuilder,
       List arguments,
       Map<String, String> environmentOverrides) {
     var exec = "$buildDir/dart_no_snapshot";
     var args = new List();
-    args.add("--full-snapshot-after-run=${computeOutputName(tempDir)}");
+    args.add("--full-snapshot-after-run=$outputName");
     args.addAll(arguments);
 
     return commandBuilder.getCompilationCommand(
-        'dart2snapshot', computeOutputName(tempDir), !useSdk,
+        'dart2snapshot', outputName, !useSdk,
         bootstrapDependencies(buildDir),
         exec, args, environmentOverrides);
   }
diff --git a/tools/testing/dart/test_configurations.dart b/tools/testing/dart/test_configurations.dart
index f4ea6d6..c7d4a09 100644
--- a/tools/testing/dart/test_configurations.dart
+++ b/tools/testing/dart/test_configurations.dart
@@ -160,7 +160,15 @@
     } else if (conf['runtime'] == 'chrome' &&
                Platform.operatingSystem == 'macos') {
       // Chrome on mac results in random timeouts.
+      // Issue: https://github.com/dart-lang/sdk/issues/23891
+      // This change does not fix the problem.
       maxBrowserProcesses = math.max(1, maxBrowserProcesses ~/ 2);
+    } else if (conf['runtime'] != 'drt') {
+      // Even on machines with more than 16 processors, don't open more
+      // than 15 browser instances, to avoid overloading the machine.
+      // This is especially important when running locally on powerful
+      // desktops.
+      maxBrowserProcesses = math.min(maxBrowserProcesses, 15);
     }
 
     // If we specifically pass in a suite only run that.
@@ -217,6 +225,7 @@
       }
     }
     DebugLogger.close();
+    TestUtils.deleteTempSnapshotDirectory(configurations[0]);
   }
 
   var eventListener = [];
diff --git a/tools/testing/dart/test_runner.dart b/tools/testing/dart/test_runner.dart
index 42dba81..a4abf47 100644
--- a/tools/testing/dart/test_runner.dart
+++ b/tools/testing/dart/test_runner.dart
@@ -1679,7 +1679,7 @@
     return new VmCommandOutputImpl(
         command, exitCode, timedOut, stdout, stderr, time, pid);
   } else if (command is CompilationCommand) {
-    if (command.displayName == 'precompiler.dart' ||
+    if (command.displayName == 'precompiler' ||
         command.displayName == 'dart2snapshot') {
       return new VmCommandOutputImpl(
           command, exitCode, timedOut, stdout, stderr, time, pid);
diff --git a/tools/testing/dart/test_suite.dart b/tools/testing/dart/test_suite.dart
index 21a99a8..fd06d20 100644
--- a/tools/testing/dart/test_suite.dart
+++ b/tools/testing/dart/test_suite.dart
@@ -16,6 +16,7 @@
 
 import "dart:async";
 import "dart:io";
+import "dart:math";
 import "drt_updater.dart";
 import "html_test.dart" as htmlTest;
 import "path.dart";
@@ -1017,14 +1018,18 @@
     List<List<String>> vmOptionsList = getVmOptions(info.optionsFromFile);
     assert(!vmOptionsList.isEmpty);
 
-    for (var vmOptions in vmOptionsList) {
+    for (var vmOptionsVarient = 0;
+         vmOptionsVarient < vmOptionsList.length;
+         vmOptionsVarient++) {
+      var vmOptions = vmOptionsList[vmOptionsVarient];
       var allVmOptions = vmOptions;
       if (!extraVmOptions.isEmpty) {
         allVmOptions = new List.from(vmOptions)..addAll(extraVmOptions);
       }
 
       var commands = []..addAll(baseCommands);
-      commands.addAll(makeCommands(info, allVmOptions, commonArguments));
+      commands.addAll(makeCommands(info, vmOptionsVarient,
+                                   allVmOptions, commonArguments));
       enqueueNewTestCase(
           new TestCase('$suiteName/$testName',
                        commands,
@@ -1049,7 +1054,10 @@
     return negative;
   }
 
-  List<Command> makeCommands(TestInformation info, var vmOptions, var args) {
+  List<Command> makeCommands(TestInformation info,
+                             int vmOptionsVarient,
+                             var vmOptions,
+                             var args) {
     List<Command> commands = <Command>[];
     CompilerConfiguration compilerConfiguration =
         new CompilerConfiguration(configuration);
@@ -1063,7 +1071,12 @@
                                                          sharedOptions,
                                                          args);
       // Avoid doing this for analyzer.
-      tempDir = createCompilationOutputDirectory(info.filePath);
+      var path = info.filePath;
+      if (vmOptionsVarient != 0) {
+        // Ensure a unique directory for each test case.
+        path = path.join(new Path(vmOptionsVarient.toString()));
+      }
+      tempDir = createCompilationOutputDirectory(path);
     }
 
     CommandArtifact compilationArtifact =
@@ -2149,6 +2162,7 @@
     dartDirUri = uri;
     dartDir = new Path(uri.toFilePath());
   }
+  static Random rand = new Random.secure();
   static Uri dartDirUri;
   static Path dartDir;
   static LastModifiedCache lastModifiedCache = new LastModifiedCache();
@@ -2157,6 +2171,13 @@
       new Path(Directory.current.path);
 
   /**
+   * Generates a random number.
+   */
+  static int getRandomNumber() {
+    return rand.nextInt(0xffffffff);
+  }
+
+  /**
    * Creates a directory using a [relativePath] to an existing
    * [base] directory if that [relativePath] does not already exist.
    */
@@ -2232,6 +2253,22 @@
     }
   }
 
+  static deleteTempSnapshotDirectory(Map configuration) {
+    if (configuration['compiler'] == 'dart2app') {
+      var checked = configuration['checked'] ? '-checked' : '';
+      var minified = configuration['minified'] ? '-minified' : '';
+      var csp = configuration['csp'] ? '-csp' : '';
+      var sdk = configuration['use_sdk'] ? '-sdk' : '';
+      var packages = configuration['use_public_packages']
+          ? '-public_packages' : '';
+      var dirName = "${configuration['compiler']}"
+          "$checked$minified$csp$packages$sdk";
+      String generatedPath = "${TestUtils.buildDir(configuration)}"
+          "/generated_compilations/$dirName";
+      TestUtils.deleteDirectory(generatedPath);
+    }
+  }
+
   static Path debugLogfile() {
     return new Path(".debug.log");
   }
diff --git a/utils/dartanalyzer/dartanalyzer.gyp b/utils/dartanalyzer/dartanalyzer.gyp
index 74dbf43..6aec554 100644
--- a/utils/dartanalyzer/dartanalyzer.gyp
+++ b/utils/dartanalyzer/dartanalyzer.gyp
@@ -34,8 +34,8 @@
           'action_name': 'generate_summaries',
           'inputs': [
             '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)dart<(EXECUTABLE_SUFFIX)',
-            '../../sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart',
             '<(SHARED_INTERMEDIATE_DIR)/packages.stamp',
+            '<!@(["python", "../../tools/list_files.py", "\\.dart$", "../../sdk/lib"])',
             '<!@(["python", "../../tools/list_files.py", "\\.dart$", "../../pkg/analyzer"])',
           ],
           'outputs': [